@oxy-hq/sdk 0.2.1 → 0.2.3
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.cjs +12 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +10 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +12 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -950,7 +950,7 @@ const OxyContext = (0, react.createContext)(void 0);
|
|
|
950
950
|
* }
|
|
951
951
|
* ```
|
|
952
952
|
*/
|
|
953
|
-
function OxyProvider({ children, config, useAsync = false, onReady, onError }) {
|
|
953
|
+
function OxyProvider({ children, config, useAsync = false, appPath, files, onReady, onError }) {
|
|
954
954
|
const [sdk, setSdk] = (0, react.useState)(null);
|
|
955
955
|
const [isLoading, setIsLoading] = (0, react.useState)(true);
|
|
956
956
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -961,8 +961,17 @@ function OxyProvider({ children, config, useAsync = false, onReady, onError }) {
|
|
|
961
961
|
try {
|
|
962
962
|
setIsLoading(true);
|
|
963
963
|
setError(null);
|
|
964
|
-
if (useAsync)
|
|
965
|
-
|
|
964
|
+
if (useAsync) {
|
|
965
|
+
sdkInstance = await OxySDK.create(config);
|
|
966
|
+
if (appPath) await sdkInstance.loadAppData(appPath);
|
|
967
|
+
if (files) {
|
|
968
|
+
const fileEntries = Object.entries(files).map(([tableName, filePath]) => ({
|
|
969
|
+
tableName,
|
|
970
|
+
filePath
|
|
971
|
+
}));
|
|
972
|
+
await sdkInstance.loadFiles(fileEntries);
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
966
975
|
if (!config) throw new Error("Config is required when useAsync is false. Either provide config or set useAsync=true.");
|
|
967
976
|
sdkInstance = new OxySDK(config);
|
|
968
977
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["isInIframe","requestAuthFromParent","duckdb","error"],"sources":["../src/config.ts","../src/parquet.ts","../src/client.ts","../src/sdk.ts","../src/react.tsx"],"sourcesContent":["/**\n * Configuration for the Oxy SDK\n */\nexport interface OxyConfig {\n /**\n * Base URL of the Oxy API (e.g., 'https://api.oxy.tech' or 'http://localhost:3000')\n */\n baseUrl: string;\n\n /**\n * API key for authentication (optional for local development)\n */\n apiKey?: string;\n\n /**\n * Project ID (UUID)\n */\n projectId: string;\n\n /**\n * Optional branch name (defaults to current branch if not specified)\n */\n branch?: string;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Parent window origin for postMessage authentication (iframe scenarios)\n * Required when using postMessage auth for security.\n * Example: 'https://app.example.com'\n * Use '*' only in development!\n */\n parentOrigin?: string;\n\n /**\n * Disable automatic postMessage authentication even if in iframe\n * Set to true if you want to provide API key manually in iframe context\n */\n disableAutoAuth?: boolean;\n}\n\n/**\n * Safely get environment variable in both Node.js and browser environments\n */\nfunction getEnvVar(name: string): string | undefined {\n // Check if we're in Node.js\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n\n // Check if we're in a Vite environment (browser)\n if (typeof import.meta !== 'undefined' && (import.meta as any).env) {\n // Try with VITE_ prefix first (Vite convention)\n const viteValue = (import.meta as any).env[`VITE_${name}`];\n if (viteValue !== undefined) return viteValue;\n\n // Try without prefix\n return (import.meta as any).env[name];\n }\n\n return undefined;\n}\n\n/**\n * Creates an Oxy configuration from environment variables\n *\n * Environment variables:\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns OxyConfig object\n * @throws Error if required environment variables are missing\n */\nexport function createConfig(overrides?: Partial<OxyConfig>): OxyConfig {\n const baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n const apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n const projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n\n/**\n * Creates an Oxy configuration asynchronously with support for postMessage authentication\n *\n * This is the recommended method for iframe scenarios where authentication\n * needs to be obtained from the parent window via postMessage.\n *\n * When running in an iframe without an API key, this function will:\n * 1. Detect the iframe context\n * 2. Send an authentication request to the parent window\n * 3. Wait for the parent to respond with credentials\n * 4. Return the configured client\n *\n * Environment variables (fallback):\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns Promise resolving to OxyConfig object\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // Automatic iframe detection and authentication\n * const config = await createConfigAsync({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n * ```\n */\nexport async function createConfigAsync(\n overrides?: Partial<OxyConfig>,\n): Promise<OxyConfig> {\n // Import postMessage utilities (dynamic to avoid circular deps)\n const { isInIframe } = await import(\"./auth/postMessage\");\n\n // Start with environment variables and overrides\n let baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n let apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n let projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n const disableAutoAuth = overrides?.disableAutoAuth ?? false;\n const parentOrigin = overrides?.parentOrigin;\n\n // Automatic iframe detection and authentication\n if (!disableAutoAuth && isInIframe() && !apiKey) {\n if (!parentOrigin) {\n logWarningAboutMissingParentOrigin();\n } else {\n apiKey = await attemptPostMessageAuth(\n parentOrigin,\n overrides?.timeout || 5000,\n apiKey,\n projectId,\n baseUrl,\n )\n .then((result) => {\n if (result.projectId) projectId = result.projectId;\n if (result.baseUrl) baseUrl = result.baseUrl;\n return result.apiKey;\n })\n .catch((error) => {\n console.error(\n \"[Oxy SDK] Failed to authenticate via postMessage:\",\n (error as Error).message,\n );\n return apiKey;\n });\n }\n }\n\n return createFinalConfig(baseUrl, apiKey, projectId, overrides);\n}\n\nfunction logWarningAboutMissingParentOrigin(): void {\n console.warn(\n \"[Oxy SDK] Running in iframe without API key and no parentOrigin specified. \" +\n \"PostMessage authentication will be skipped. \" +\n \"Provide parentOrigin config to enable automatic authentication.\",\n );\n}\n\nasync function attemptPostMessageAuth(\n parentOrigin: string,\n timeout: number,\n currentApiKey: string | undefined,\n currentProjectId: string | undefined,\n currentBaseUrl: string | undefined,\n): Promise<{ apiKey?: string; projectId?: string; baseUrl?: string }> {\n const { requestAuthFromParent } = await import(\"./auth/postMessage\");\n const authResult = await requestAuthFromParent({ parentOrigin, timeout });\n\n console.log(\"[Oxy SDK] Successfully authenticated via postMessage\");\n\n return {\n apiKey: authResult.apiKey || currentApiKey,\n projectId: authResult.projectId || currentProjectId,\n baseUrl: authResult.baseUrl || currentBaseUrl,\n };\n}\n\nfunction createFinalConfig(\n baseUrl: string | undefined,\n apiKey: string | undefined,\n projectId: string | undefined,\n overrides?: Partial<OxyConfig>,\n): OxyConfig {\n // Validation\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n","import * as duckdb from \"@duckdb/duckdb-wasm\";\n\nlet dbInstance: duckdb.AsyncDuckDB | null = null;\nlet connection: duckdb.AsyncDuckDBConnection | null = null;\n\n// Queue to serialize operations and prevent race conditions\nlet operationQueue = Promise.resolve();\n\n/**\n * Enqueue an operation to prevent race conditions on shared DuckDB instance\n */\nfunction enqueueOperation<T>(operation: () => Promise<T>): Promise<T> {\n const currentOperation = operationQueue.then(operation, operation);\n operationQueue = currentOperation.then(\n () => {\n return;\n },\n () => {\n return;\n },\n );\n return currentOperation;\n}\n\n/**\n * Initialize DuckDB-WASM instance\n */\nexport async function initializeDuckDB(): Promise<duckdb.AsyncDuckDB> {\n if (dbInstance) {\n return dbInstance;\n }\n\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();\n\n // Select a bundle based on browser features\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);\n\n const worker_url = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], {\n type: \"text/javascript\",\n }),\n );\n\n const worker = new Worker(worker_url);\n const logger = new duckdb.ConsoleLogger();\n\n dbInstance = new duckdb.AsyncDuckDB(logger, worker);\n await dbInstance.instantiate(bundle.mainModule, bundle.pthreadWorker);\n URL.revokeObjectURL(worker_url);\n\n return dbInstance;\n}\n\n/**\n * Get or create a DuckDB connection\n */\nasync function getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (connection) {\n return connection;\n }\n\n const db = await initializeDuckDB();\n connection = await db.connect();\n return connection;\n}\n\n/**\n * Query result interface\n */\nexport interface QueryResult {\n columns: string[];\n rows: unknown[][];\n rowCount: number;\n}\n\n/**\n * ParquetReader provides methods to read and query Parquet files.\n * Supports registering multiple Parquet files with different table names.\n */\nexport class ParquetReader {\n private tableMap: Map<string, string> = new Map(); // Maps user table name -> internal unique table name\n\n constructor() {\n // No default table name - all tables must be explicitly named\n }\n\n /**\n * Generate a unique internal table name to prevent conflicts\n */\n private generateInternalTableName(tableName: string): string {\n // Note: Math.random() is acceptable here as uniqueness is only needed for table naming (not security-critical)\n /* eslint-disable sonarjs/pseudo-random */\n const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n /* eslint-enable sonarjs/pseudo-random */\n return `${tableName}_${uniqueId}`;\n }\n\n /**\n * Register a Parquet file from a Blob with a specific table name\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (required)\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const reader = new ParquetReader();\n * await reader.registerParquet(blob, 'sales');\n * ```\n *\n * @example\n * ```typescript\n * // Register multiple files\n * const reader = new ParquetReader();\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerParquet(blob: Blob, tableName: string): Promise<void> {\n const internalTableName = this.generateInternalTableName(tableName);\n\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Convert blob to Uint8Array\n const arrayBuffer = await blob.arrayBuffer();\n const uint8Array = new Uint8Array(arrayBuffer);\n\n // Register the file with DuckDB using unique name\n await db.registerFileBuffer(\n `${internalTableName}.parquet`,\n uint8Array,\n );\n\n // Drop table if it exists\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error if table doesn't exist\n }\n\n // Create table from parquet\n await conn.query(\n `CREATE TABLE ${internalTableName} AS SELECT * FROM '${internalTableName}.parquet'`,\n );\n\n // Store mapping\n this.tableMap.set(tableName, internalTableName);\n });\n }\n\n /**\n * Register multiple Parquet files at once\n *\n * @param files - Array of objects containing blob and tableName\n *\n * @example\n * ```typescript\n * const reader = new ParquetReader();\n * await reader.registerMultipleParquet([\n * { blob: salesBlob, tableName: 'sales' },\n * { blob: customersBlob, tableName: 'customers' },\n * { blob: productsBlob, tableName: 'products' }\n * ]);\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerMultipleParquet(\n files: Array<{ blob: Blob; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.registerParquet(file.blob, file.tableName);\n }\n }\n\n /**\n * Execute a SQL query against the registered Parquet data\n *\n * @param sql - SQL query string\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * const result = await reader.query('SELECT * FROM sales LIMIT 10');\n * console.log(result.columns);\n * console.log(result.rows);\n * ```\n *\n * @example\n * ```typescript\n * // Query multiple tables\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n if (this.tableMap.size === 0) {\n throw new Error(\n \"No Parquet files registered. Call registerParquet() first.\",\n );\n }\n\n return enqueueOperation(async () => {\n const conn = await getConnection();\n\n // Replace all registered table names with their internal unique names\n let rewrittenSql = sql;\n for (const [userTableName, internalTableName] of this.tableMap.entries()) {\n rewrittenSql = rewrittenSql.replace(\n new RegExp(`\\\\b${userTableName}\\\\b`, \"g\"),\n internalTableName,\n );\n }\n\n const result = await conn.query(rewrittenSql);\n\n const columns = result.schema.fields.map((field) => field.name);\n const rows: unknown[][] = [];\n\n // Convert Arrow table to rows\n for (let i = 0; i < result.numRows; i++) {\n const row: unknown[] = [];\n for (let j = 0; j < result.numCols; j++) {\n const col = result.getChildAt(j);\n row.push(col?.get(i));\n }\n rows.push(row);\n }\n\n return {\n columns,\n rows,\n rowCount: result.numRows,\n };\n });\n }\n\n /**\n * Get all data from a registered table\n *\n * @param tableName - Name of the table to query\n * @param limit - Maximum number of rows to return (default: all)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const allData = await reader.getAll('sales');\n * const first100 = await reader.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n const limitClause = limit ? ` LIMIT ${limit}` : \"\";\n return this.query(`SELECT * FROM ${tableName}${limitClause}`);\n }\n\n /**\n * Get table schema information\n *\n * @param tableName - Name of the table to describe\n * @returns Schema information\n *\n * @example\n * ```typescript\n * const schema = await reader.getSchema('sales');\n * console.log(schema.columns); // ['id', 'name', 'sales']\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.query(`DESCRIBE ${tableName}`);\n }\n\n /**\n * Get row count for a table\n *\n * @param tableName - Name of the table to count\n * @returns Number of rows in the table\n *\n * @example\n * ```typescript\n * const count = await reader.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n const result = await this.query(\n `SELECT COUNT(*) as count FROM ${tableName}`,\n );\n return result.rows[0][0] as number;\n }\n\n /**\n * Close and cleanup all registered resources\n */\n async close(): Promise<void> {\n if (this.tableMap.size > 0) {\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Drop all registered tables and file buffers\n for (const [, internalTableName] of this.tableMap.entries()) {\n // Drop the table using internal unique name\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error\n }\n\n // Drop the registered file buffer using internal unique name\n try {\n await db.dropFile(`${internalTableName}.parquet`);\n } catch {\n // Ignore error if file doesn't exist\n }\n }\n\n // Clear the table map\n this.tableMap.clear();\n });\n }\n }\n}\n\n/**\n * Helper function to quickly read a Parquet blob and execute a query\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (default: 'data')\n * @param sql - SQL query to execute (optional, defaults to SELECT * FROM tableName)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const result = await queryParquet(blob, 'sales', 'SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result);\n * ```\n */\nexport async function queryParquet(\n blob: Blob,\n tableName: string = \"data\",\n sql?: string,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const query = sql || `SELECT * FROM ${tableName}`;\n const result = await reader.query(query);\n\n await reader.close();\n return result;\n}\n\n/**\n * Helper function to read Parquet file and get all data\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table (default: 'data')\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const data = await readParquet(blob, 'sales', 1000);\n * console.log(`Loaded ${data.rowCount} rows`);\n * ```\n */\nexport async function readParquet(\n blob: Blob,\n tableName: string = \"data\",\n limit?: number,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const result = await reader.getAll(tableName, limit);\n\n await reader.close();\n return result;\n}\n","import { OxyConfig, createConfigAsync } from \"./config\";\nimport {\n AppItem,\n AppDataResponse,\n GetDisplaysResponse,\n ApiError,\n TableData,\n} from \"./types\";\nimport { readParquet } from \"./parquet\";\n\n/**\n * Oxy API Client for interacting with Oxy data\n */\nexport class OxyClient {\n private config: OxyConfig;\n\n constructor(config: OxyConfig) {\n this.config = config;\n }\n\n /**\n * Creates an OxyClient instance asynchronously with support for postMessage authentication\n *\n * This is the recommended method when using the SDK in an iframe that needs to\n * obtain authentication from the parent window via postMessage.\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxyClient instance\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const client = await OxyClient.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n *\n * // Use the client normally\n * const apps = await client.listApps();\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxyClient> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxyClient(resolvedConfig);\n }\n\n /**\n * Encodes a file path to base64 for use in API URLs\n */\n private encodePathBase64(path: string): string {\n if (typeof Buffer !== \"undefined\") {\n // Node.js environment\n return Buffer.from(path).toString(\"base64\");\n } else {\n // Browser environment\n return btoa(path);\n }\n }\n\n /**\n * Makes an authenticated HTTP request to the Oxy API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...((options.headers as Record<string, string>) || {}),\n };\n\n // Only add Authorization header if API key is provided (optional for local dev)\n if (this.config.apiKey) {\n headers[\"Authorization\"] = `Bearer ${this.config.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.timeout || 30000,\n );\n\n try {\n const response = await fetch(url, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n const error: ApiError = {\n message: `API request failed: ${response.statusText}`,\n status: response.status,\n details: errorText,\n };\n throw error;\n }\n\n // Handle binary responses\n const acceptHeader =\n typeof options.headers === \"object\" && options.headers !== null\n ? (options.headers as Record<string, string>)[\"Accept\"]\n : undefined;\n if (acceptHeader === \"application/octet-stream\") {\n return response.blob() as Promise<T>;\n }\n\n return response.json();\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\n `Request timeout after ${this.config.timeout || 30000}ms`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Builds query parameters including optional branch\n */\n private buildQueryParams(\n additionalParams: Record<string, string> = {},\n ): string {\n const params: Record<string, string> = { ...additionalParams };\n\n if (this.config.branch) {\n params.branch = this.config.branch;\n }\n\n const searchParams = new URLSearchParams(params);\n const queryString = searchParams.toString();\n return queryString ? `?${queryString}` : \"\";\n }\n\n /**\n * Lists all apps in the project\n *\n * @returns Array of app items\n *\n * @example\n * ```typescript\n * const apps = await client.listApps();\n * console.log('Available apps:', apps);\n * ```\n */\n async listApps(): Promise<AppItem[]> {\n const query = this.buildQueryParams();\n return this.request<AppItem[]>(`/${this.config.projectId}/app${query}`);\n }\n\n /**\n * Gets data for a specific app\n *\n * @param appPath - Relative path to the app file (e.g., 'my-app.app.yml')\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.getAppData('dashboard.app.yml');\n * if (data.error) {\n * console.error('Error:', data.error);\n * } else {\n * console.log('App data:', data.data);\n * }\n * ```\n */\n async getAppData(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}${query}`,\n );\n }\n\n /**\n * Runs an app and returns fresh data (bypasses cache)\n *\n * @param appPath - Relative path to the app file\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.runApp('dashboard.app.yml');\n * console.log('Fresh app data:', data.data);\n * ```\n */\n async runApp(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}/run${query}`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Gets display configurations for an app\n *\n * @param appPath - Relative path to the app file\n * @returns Display configurations with potential errors\n *\n * @example\n * ```typescript\n * const displays = await client.getDisplays('dashboard.app.yml');\n * displays.displays.forEach(d => {\n * if (d.error) {\n * console.error('Display error:', d.error);\n * } else {\n * console.log('Display:', d.display);\n * }\n * });\n * ```\n */\n async getDisplays(appPath: string): Promise<GetDisplaysResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<GetDisplaysResponse>(\n `/${this.config.projectId}/app/${pathb64}/displays${query}`,\n );\n }\n\n /**\n * Gets a file from the app state directory (e.g., generated charts, images)\n *\n * This is useful for retrieving generated assets like charts, images, or other\n * files produced by app workflows and stored in the state directory.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Blob containing the file data\n *\n * @example\n * ```typescript\n * // Get a generated chart image\n * const blob = await client.getFile('charts/sales-chart.png');\n * const imageUrl = URL.createObjectURL(blob);\n *\n * // Use in an img tag\n * document.querySelector('img').src = imageUrl;\n * ```\n *\n * @example\n * ```typescript\n * // Download a file\n * const blob = await client.getFile('exports/data.csv');\n * const a = document.createElement('a');\n * a.href = URL.createObjectURL(blob);\n * a.download = 'data.csv';\n * a.click();\n * ```\n */\n async getFile(filePath: string): Promise<Blob> {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return this.request<Blob>(\n `/${this.config.projectId}/app/file/${pathb64}${query}`,\n {\n headers: {\n Accept: \"application/octet-stream\",\n },\n },\n );\n }\n\n /**\n * Gets a file URL for direct browser access\n *\n * This returns a URL that can be used directly in img tags, fetch calls, etc.\n * The URL includes authentication via query parameters.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Full URL to the file\n *\n * @example\n * ```typescript\n * const imageUrl = client.getFileUrl('charts/sales-chart.png');\n *\n * // Use directly in img tag (in environments where query-based auth is supported)\n * document.querySelector('img').src = imageUrl;\n * ```\n */\n getFileUrl(filePath: string): string {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return `${this.config.baseUrl}/${this.config.projectId}/app/file/${pathb64}${query}`;\n }\n\n /**\n * Fetches a parquet file and parses it into table data\n *\n * @param filePath - Relative path to the parquet file\n * @param limit - Maximum number of rows to return (default: 100)\n * @returns TableData with columns and rows\n *\n * @example\n * ```typescript\n * const tableData = await client.getTableData('data/sales.parquet', 50);\n * console.log(tableData.columns);\n * console.log(tableData.rows);\n * console.log(`Total rows: ${tableData.total_rows}`);\n * ```\n */\n async getTableData(\n filePath: string,\n limit: number = 100,\n ): Promise<TableData> {\n const blob = await this.getFile(filePath);\n const result = await readParquet(blob, \"data\", limit);\n\n return {\n columns: result.columns,\n rows: result.rows,\n total_rows: result.rowCount,\n };\n }\n}\n","import { OxyClient } from \"./client\";\nimport { OxyConfig, createConfigAsync } from \"./config\";\nimport { ParquetReader, QueryResult } from \"./parquet\";\nimport { DataContainer } from \"./types\";\n\n/**\n * OxySDK provides a unified interface for fetching data from Oxy and querying it with SQL.\n * It combines OxyClient (for API calls) and ParquetReader (for SQL queries) into a single,\n * easy-to-use interface.\n *\n * @example\n * ```typescript\n * // Create SDK instance\n * const sdk = new OxySDK({ apiKey: 'your-key', projectId: 'your-project' });\n *\n * // Load a parquet file and query it\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales WHERE amount > 1000');\n * console.log(result.rows);\n *\n * // Clean up when done\n * await sdk.close();\n * ```\n */\nexport class OxySDK {\n private client: OxyClient;\n private reader: ParquetReader;\n\n constructor(config: OxyConfig) {\n this.client = new OxyClient(config);\n this.reader = new ParquetReader();\n }\n\n /**\n * Creates an OxySDK instance asynchronously with support for postMessage authentication\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxySDK instance\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const sdk = await OxySDK.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id'\n * });\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxySDK> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxySDK(resolvedConfig);\n }\n\n /**\n * Load a Parquet file from Oxy and register it for SQL queries\n *\n * @param filePath - Path to the parquet file in the app state directory\n * @param tableName - Name to use for the table in SQL queries\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * await sdk.loadFile('data/customers.parquet', 'customers');\n *\n * const result = await sdk.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async loadFile(filePath: string, tableName: string): Promise<void> {\n const blob = await this.client.getFile(filePath);\n await this.reader.registerParquet(blob, tableName);\n }\n\n /**\n * Load multiple Parquet files at once\n *\n * @param files - Array of file paths and table names\n *\n * @example\n * ```typescript\n * await sdk.loadFiles([\n * { filePath: 'data/sales.parquet', tableName: 'sales' },\n * { filePath: 'data/customers.parquet', tableName: 'customers' },\n * { filePath: 'data/products.parquet', tableName: 'products' }\n * ]);\n *\n * const result = await sdk.query('SELECT * FROM sales');\n * ```\n */\n async loadFiles(\n files: Array<{ filePath: string; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.loadFile(file.filePath, file.tableName);\n }\n }\n\n /**\n * Load all data from an app's data container\n *\n * This fetches the app's data and registers all parquet files using their container keys as table names.\n *\n * @param appPath - Path to the app file\n * @returns DataContainer with file references\n *\n * @example\n * ```typescript\n * // If app has data: { sales: { file_path: 'data/sales.parquet' } }\n * const data = await sdk.loadAppData('dashboard.app.yml');\n * // Now you can query the 'sales' table\n * const result = await sdk.query('SELECT * FROM sales LIMIT 10');\n * ```\n */\n async loadAppData(appPath: string): Promise<DataContainer | null> {\n const appDataResponse = await this.client.getAppData(appPath);\n\n if (appDataResponse.error) {\n throw new Error(`Failed to load app data: ${appDataResponse.error}`);\n }\n\n if (!appDataResponse.data) {\n return null;\n }\n\n // Load each file in the data container\n const loadPromises = Object.entries(appDataResponse.data).map(\n async ([tableName, fileRef]) => {\n await this.loadFile(fileRef.file_path, tableName);\n },\n );\n\n await Promise.all(loadPromises);\n\n return appDataResponse.data;\n }\n\n /**\n * Execute a SQL query against loaded data\n *\n * @param sql - SQL query to execute\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n *\n * const result = await sdk.query('SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result.columns); // ['product', 'total']\n * console.log(result.rows); // [['Product A', 1000], ['Product B', 2000]]\n * console.log(result.rowCount); // 2\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n return this.reader.query(sql);\n }\n\n /**\n * Get all data from a loaded table\n *\n * @param tableName - Name of the table\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const allData = await sdk.getAll('sales');\n * const first100 = await sdk.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n return this.reader.getAll(tableName, limit);\n }\n\n /**\n * Get schema information for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Schema information\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const schema = await sdk.getSchema('sales');\n * console.log(schema.columns); // ['column_name', 'column_type', ...]\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.reader.getSchema(tableName);\n }\n\n /**\n * Get row count for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Number of rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const count = await sdk.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n return this.reader.count(tableName);\n }\n\n /**\n * Get direct access to the underlying OxyClient\n *\n * Useful for advanced operations like listing apps, getting displays, etc.\n *\n * @returns The OxyClient instance\n *\n * @example\n * ```typescript\n * const apps = await sdk.getClient().listApps();\n * const displays = await sdk.getClient().getDisplays('my-app.app.yml');\n * ```\n */\n getClient(): OxyClient {\n return this.client;\n }\n\n /**\n * Get direct access to the underlying ParquetReader\n *\n * Useful for advanced operations like registering blobs directly.\n *\n * @returns The ParquetReader instance\n *\n * @example\n * ```typescript\n * const myBlob = new Blob([parquetData]);\n * await sdk.getReader().registerParquet(myBlob, 'mydata');\n * ```\n */\n getReader(): ParquetReader {\n return this.reader;\n }\n\n /**\n * Close and cleanup all resources\n *\n * This clears all loaded data and releases resources. Call this when you're done with the SDK.\n *\n * @example\n * ```typescript\n * const sdk = new OxySDK({ apiKey: 'key', projectId: 'project' });\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales');\n * await sdk.close(); // Clean up\n * ```\n */\n async close(): Promise<void> {\n await this.reader.close();\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n ReactNode,\n} from \"react\";\nimport { OxySDK } from \"./sdk\";\nimport { OxyConfig } from \"./config\";\n\n/**\n * Context value provided to child components\n */\nexport interface OxyContextValue {\n sdk: OxySDK | null;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * React context for OxySDK\n */\nconst OxyContext = createContext<OxyContextValue | undefined>(undefined);\n\n/**\n * Props for OxyProvider component\n */\nexport interface OxyProviderProps {\n children: ReactNode;\n config?: Partial<OxyConfig>;\n /**\n * If true, uses async initialization (supports postMessage auth in iframes)\n * If false, uses synchronous initialization with provided config\n */\n useAsync?: boolean;\n /**\n * Called when SDK is successfully initialized\n */\n onReady?: (sdk: OxySDK) => void;\n /**\n * Called when initialization fails\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Provider component that initializes and provides OxySDK to child components\n *\n * @example\n * ```tsx\n * // Synchronous initialization with config\n * function App() {\n * return (\n * <OxyProvider config={{\n * apiKey: 'your-key',\n * projectId: 'your-project',\n * baseUrl: 'https://api.oxy.tech'\n * }}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Async initialization (for iframe/postMessage auth)\n * function App() {\n * return (\n * <OxyProvider\n * useAsync\n * config={{ parentOrigin: 'https://app.example.com' }}\n * >\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With environment variables\n * import { createConfig } from '@oxy/sdk';\n *\n * function App() {\n * return (\n * <OxyProvider config={createConfig()}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n */\nexport function OxyProvider({\n children,\n config,\n useAsync = false,\n onReady,\n onError,\n}: OxyProviderProps) {\n const [sdk, setSdk] = useState<OxySDK | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n let sdkInstance: OxySDK | null = null;\n\n async function initializeSDK() {\n try {\n setIsLoading(true);\n setError(null);\n\n if (useAsync) {\n // Async initialization (supports postMessage auth)\n sdkInstance = await OxySDK.create(config);\n } else {\n // Sync initialization with provided config\n if (!config) {\n throw new Error(\n \"Config is required when useAsync is false. Either provide config or set useAsync=true.\",\n );\n }\n sdkInstance = new OxySDK(config as OxyConfig);\n }\n\n if (mounted) {\n setSdk(sdkInstance);\n setIsLoading(false);\n onReady?.(sdkInstance);\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Failed to initialize SDK\");\n\n if (mounted) {\n setError(error);\n setIsLoading(false);\n onError?.(error);\n }\n }\n }\n\n initializeSDK();\n\n // Cleanup function\n return () => {\n mounted = false;\n if (sdkInstance) {\n sdkInstance.close().catch(console.error);\n }\n };\n }, [config, useAsync, onReady, onError]);\n\n return (\n <OxyContext.Provider value={{ sdk, isLoading, error }}>\n {children}\n </OxyContext.Provider>\n );\n}\n\n/**\n * Hook to access OxySDK from child components\n *\n * @throws {Error} If used outside of OxyProvider\n * @returns {OxyContextValue} The SDK instance, loading state, and error\n *\n * @example\n * ```tsx\n * function Dashboard() {\n * const { sdk, isLoading, error } = useOxy();\n *\n * useEffect(() => {\n * if (sdk) {\n * sdk.loadAppData('dashboard.app.yml')\n * .then(() => sdk.query('SELECT * FROM my_table'))\n * .then(result => console.log(result));\n * }\n * }, [sdk]);\n *\n * if (isLoading) return <div>Loading SDK...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!sdk) return null;\n *\n * return <div>Dashboard</div>;\n * }\n * ```\n */\nexport function useOxy(): OxyContextValue {\n const context = useContext(OxyContext);\n\n if (context === undefined) {\n throw new Error(\"useOxy must be used within an OxyProvider\");\n }\n\n return context;\n}\n\n/**\n * Hook to access OxySDK that throws if not ready\n *\n * This is a convenience hook that returns the SDK directly or throws an error if not initialized.\n * Use this when you know the SDK should be ready.\n *\n * @throws {Error} If used outside of OxyProvider or if SDK is not initialized\n * @returns {OxySDK} The SDK instance\n *\n * @example\n * ```tsx\n * function DataTable() {\n * const sdk = useOxySDK();\n * const [data, setData] = useState(null);\n *\n * useEffect(() => {\n * sdk.loadFile('data.parquet', 'data')\n * .then(() => sdk.query('SELECT * FROM data LIMIT 100'))\n * .then(setData);\n * }, [sdk]);\n *\n * return <table>...</table>;\n * }\n * ```\n */\nexport function useOxySDK(): OxySDK {\n const { sdk, isLoading, error } = useOxy();\n\n if (error) {\n throw error;\n }\n\n if (isLoading || !sdk) {\n throw new Error(\"OxySDK is not yet initialized\");\n }\n\n return sdk;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["isInIframe","requestAuthFromParent","duckdb","error"],"sources":["../src/config.ts","../src/parquet.ts","../src/client.ts","../src/sdk.ts","../src/react.tsx"],"sourcesContent":["/**\n * Configuration for the Oxy SDK\n */\nexport interface OxyConfig {\n /**\n * Base URL of the Oxy API (e.g., 'https://api.oxy.tech' or 'http://localhost:3000')\n */\n baseUrl: string;\n\n /**\n * API key for authentication (optional for local development)\n */\n apiKey?: string;\n\n /**\n * Project ID (UUID)\n */\n projectId: string;\n\n /**\n * Optional branch name (defaults to current branch if not specified)\n */\n branch?: string;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Parent window origin for postMessage authentication (iframe scenarios)\n * Required when using postMessage auth for security.\n * Example: 'https://app.example.com'\n * Use '*' only in development!\n */\n parentOrigin?: string;\n\n /**\n * Disable automatic postMessage authentication even if in iframe\n * Set to true if you want to provide API key manually in iframe context\n */\n disableAutoAuth?: boolean;\n}\n\n/**\n * Safely get environment variable in both Node.js and browser environments\n */\nfunction getEnvVar(name: string): string | undefined {\n // Check if we're in Node.js\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n\n // Check if we're in a Vite environment (browser)\n if (typeof import.meta !== 'undefined' && (import.meta as any).env) {\n // Try with VITE_ prefix first (Vite convention)\n const viteValue = (import.meta as any).env[`VITE_${name}`];\n if (viteValue !== undefined) return viteValue;\n\n // Try without prefix\n return (import.meta as any).env[name];\n }\n\n return undefined;\n}\n\n/**\n * Creates an Oxy configuration from environment variables\n *\n * Environment variables:\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns OxyConfig object\n * @throws Error if required environment variables are missing\n */\nexport function createConfig(overrides?: Partial<OxyConfig>): OxyConfig {\n const baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n const apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n const projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n\n/**\n * Creates an Oxy configuration asynchronously with support for postMessage authentication\n *\n * This is the recommended method for iframe scenarios where authentication\n * needs to be obtained from the parent window via postMessage.\n *\n * When running in an iframe without an API key, this function will:\n * 1. Detect the iframe context\n * 2. Send an authentication request to the parent window\n * 3. Wait for the parent to respond with credentials\n * 4. Return the configured client\n *\n * Environment variables (fallback):\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns Promise resolving to OxyConfig object\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // Automatic iframe detection and authentication\n * const config = await createConfigAsync({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n * ```\n */\nexport async function createConfigAsync(\n overrides?: Partial<OxyConfig>,\n): Promise<OxyConfig> {\n // Import postMessage utilities (dynamic to avoid circular deps)\n const { isInIframe } = await import(\"./auth/postMessage\");\n\n // Start with environment variables and overrides\n let baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n let apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n let projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n const disableAutoAuth = overrides?.disableAutoAuth ?? false;\n const parentOrigin = overrides?.parentOrigin;\n\n // Automatic iframe detection and authentication\n if (!disableAutoAuth && isInIframe() && !apiKey) {\n if (!parentOrigin) {\n logWarningAboutMissingParentOrigin();\n } else {\n apiKey = await attemptPostMessageAuth(\n parentOrigin,\n overrides?.timeout || 5000,\n apiKey,\n projectId,\n baseUrl,\n )\n .then((result) => {\n if (result.projectId) projectId = result.projectId;\n if (result.baseUrl) baseUrl = result.baseUrl;\n return result.apiKey;\n })\n .catch((error) => {\n console.error(\n \"[Oxy SDK] Failed to authenticate via postMessage:\",\n (error as Error).message,\n );\n return apiKey;\n });\n }\n }\n\n return createFinalConfig(baseUrl, apiKey, projectId, overrides);\n}\n\nfunction logWarningAboutMissingParentOrigin(): void {\n console.warn(\n \"[Oxy SDK] Running in iframe without API key and no parentOrigin specified. \" +\n \"PostMessage authentication will be skipped. \" +\n \"Provide parentOrigin config to enable automatic authentication.\",\n );\n}\n\nasync function attemptPostMessageAuth(\n parentOrigin: string,\n timeout: number,\n currentApiKey: string | undefined,\n currentProjectId: string | undefined,\n currentBaseUrl: string | undefined,\n): Promise<{ apiKey?: string; projectId?: string; baseUrl?: string }> {\n const { requestAuthFromParent } = await import(\"./auth/postMessage\");\n const authResult = await requestAuthFromParent({ parentOrigin, timeout });\n\n console.log(\"[Oxy SDK] Successfully authenticated via postMessage\");\n\n return {\n apiKey: authResult.apiKey || currentApiKey,\n projectId: authResult.projectId || currentProjectId,\n baseUrl: authResult.baseUrl || currentBaseUrl,\n };\n}\n\nfunction createFinalConfig(\n baseUrl: string | undefined,\n apiKey: string | undefined,\n projectId: string | undefined,\n overrides?: Partial<OxyConfig>,\n): OxyConfig {\n // Validation\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n","import * as duckdb from \"@duckdb/duckdb-wasm\";\n\nlet dbInstance: duckdb.AsyncDuckDB | null = null;\nlet connection: duckdb.AsyncDuckDBConnection | null = null;\n\n// Queue to serialize operations and prevent race conditions\nlet operationQueue = Promise.resolve();\n\n/**\n * Enqueue an operation to prevent race conditions on shared DuckDB instance\n */\nfunction enqueueOperation<T>(operation: () => Promise<T>): Promise<T> {\n const currentOperation = operationQueue.then(operation, operation);\n operationQueue = currentOperation.then(\n () => {\n return;\n },\n () => {\n return;\n },\n );\n return currentOperation;\n}\n\n/**\n * Initialize DuckDB-WASM instance\n */\nexport async function initializeDuckDB(): Promise<duckdb.AsyncDuckDB> {\n if (dbInstance) {\n return dbInstance;\n }\n\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();\n\n // Select a bundle based on browser features\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);\n\n const worker_url = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], {\n type: \"text/javascript\",\n }),\n );\n\n const worker = new Worker(worker_url);\n const logger = new duckdb.ConsoleLogger();\n\n dbInstance = new duckdb.AsyncDuckDB(logger, worker);\n await dbInstance.instantiate(bundle.mainModule, bundle.pthreadWorker);\n URL.revokeObjectURL(worker_url);\n\n return dbInstance;\n}\n\n/**\n * Get or create a DuckDB connection\n */\nasync function getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (connection) {\n return connection;\n }\n\n const db = await initializeDuckDB();\n connection = await db.connect();\n return connection;\n}\n\n/**\n * Query result interface\n */\nexport interface QueryResult {\n columns: string[];\n rows: unknown[][];\n rowCount: number;\n}\n\n/**\n * ParquetReader provides methods to read and query Parquet files.\n * Supports registering multiple Parquet files with different table names.\n */\nexport class ParquetReader {\n private tableMap: Map<string, string> = new Map(); // Maps user table name -> internal unique table name\n\n constructor() {\n // No default table name - all tables must be explicitly named\n }\n\n /**\n * Generate a unique internal table name to prevent conflicts\n */\n private generateInternalTableName(tableName: string): string {\n // Note: Math.random() is acceptable here as uniqueness is only needed for table naming (not security-critical)\n /* eslint-disable sonarjs/pseudo-random */\n const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n /* eslint-enable sonarjs/pseudo-random */\n return `${tableName}_${uniqueId}`;\n }\n\n /**\n * Register a Parquet file from a Blob with a specific table name\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (required)\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const reader = new ParquetReader();\n * await reader.registerParquet(blob, 'sales');\n * ```\n *\n * @example\n * ```typescript\n * // Register multiple files\n * const reader = new ParquetReader();\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerParquet(blob: Blob, tableName: string): Promise<void> {\n const internalTableName = this.generateInternalTableName(tableName);\n\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Convert blob to Uint8Array\n const arrayBuffer = await blob.arrayBuffer();\n const uint8Array = new Uint8Array(arrayBuffer);\n\n // Register the file with DuckDB using unique name\n await db.registerFileBuffer(\n `${internalTableName}.parquet`,\n uint8Array,\n );\n\n // Drop table if it exists\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error if table doesn't exist\n }\n\n // Create table from parquet\n await conn.query(\n `CREATE TABLE ${internalTableName} AS SELECT * FROM '${internalTableName}.parquet'`,\n );\n\n // Store mapping\n this.tableMap.set(tableName, internalTableName);\n });\n }\n\n /**\n * Register multiple Parquet files at once\n *\n * @param files - Array of objects containing blob and tableName\n *\n * @example\n * ```typescript\n * const reader = new ParquetReader();\n * await reader.registerMultipleParquet([\n * { blob: salesBlob, tableName: 'sales' },\n * { blob: customersBlob, tableName: 'customers' },\n * { blob: productsBlob, tableName: 'products' }\n * ]);\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerMultipleParquet(\n files: Array<{ blob: Blob; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.registerParquet(file.blob, file.tableName);\n }\n }\n\n /**\n * Execute a SQL query against the registered Parquet data\n *\n * @param sql - SQL query string\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * const result = await reader.query('SELECT * FROM sales LIMIT 10');\n * console.log(result.columns);\n * console.log(result.rows);\n * ```\n *\n * @example\n * ```typescript\n * // Query multiple tables\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n if (this.tableMap.size === 0) {\n throw new Error(\n \"No Parquet files registered. Call registerParquet() first.\",\n );\n }\n\n return enqueueOperation(async () => {\n const conn = await getConnection();\n\n // Replace all registered table names with their internal unique names\n let rewrittenSql = sql;\n for (const [userTableName, internalTableName] of this.tableMap.entries()) {\n rewrittenSql = rewrittenSql.replace(\n new RegExp(`\\\\b${userTableName}\\\\b`, \"g\"),\n internalTableName,\n );\n }\n\n const result = await conn.query(rewrittenSql);\n\n const columns = result.schema.fields.map((field) => field.name);\n const rows: unknown[][] = [];\n\n // Convert Arrow table to rows\n for (let i = 0; i < result.numRows; i++) {\n const row: unknown[] = [];\n for (let j = 0; j < result.numCols; j++) {\n const col = result.getChildAt(j);\n row.push(col?.get(i));\n }\n rows.push(row);\n }\n\n return {\n columns,\n rows,\n rowCount: result.numRows,\n };\n });\n }\n\n /**\n * Get all data from a registered table\n *\n * @param tableName - Name of the table to query\n * @param limit - Maximum number of rows to return (default: all)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const allData = await reader.getAll('sales');\n * const first100 = await reader.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n const limitClause = limit ? ` LIMIT ${limit}` : \"\";\n return this.query(`SELECT * FROM ${tableName}${limitClause}`);\n }\n\n /**\n * Get table schema information\n *\n * @param tableName - Name of the table to describe\n * @returns Schema information\n *\n * @example\n * ```typescript\n * const schema = await reader.getSchema('sales');\n * console.log(schema.columns); // ['id', 'name', 'sales']\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.query(`DESCRIBE ${tableName}`);\n }\n\n /**\n * Get row count for a table\n *\n * @param tableName - Name of the table to count\n * @returns Number of rows in the table\n *\n * @example\n * ```typescript\n * const count = await reader.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n const result = await this.query(\n `SELECT COUNT(*) as count FROM ${tableName}`,\n );\n return result.rows[0][0] as number;\n }\n\n /**\n * Close and cleanup all registered resources\n */\n async close(): Promise<void> {\n if (this.tableMap.size > 0) {\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Drop all registered tables and file buffers\n for (const [, internalTableName] of this.tableMap.entries()) {\n // Drop the table using internal unique name\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error\n }\n\n // Drop the registered file buffer using internal unique name\n try {\n await db.dropFile(`${internalTableName}.parquet`);\n } catch {\n // Ignore error if file doesn't exist\n }\n }\n\n // Clear the table map\n this.tableMap.clear();\n });\n }\n }\n}\n\n/**\n * Helper function to quickly read a Parquet blob and execute a query\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (default: 'data')\n * @param sql - SQL query to execute (optional, defaults to SELECT * FROM tableName)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const result = await queryParquet(blob, 'sales', 'SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result);\n * ```\n */\nexport async function queryParquet(\n blob: Blob,\n tableName: string = \"data\",\n sql?: string,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const query = sql || `SELECT * FROM ${tableName}`;\n const result = await reader.query(query);\n\n await reader.close();\n return result;\n}\n\n/**\n * Helper function to read Parquet file and get all data\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table (default: 'data')\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const data = await readParquet(blob, 'sales', 1000);\n * console.log(`Loaded ${data.rowCount} rows`);\n * ```\n */\nexport async function readParquet(\n blob: Blob,\n tableName: string = \"data\",\n limit?: number,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const result = await reader.getAll(tableName, limit);\n\n await reader.close();\n return result;\n}\n","import { OxyConfig, createConfigAsync } from \"./config\";\nimport {\n AppItem,\n AppDataResponse,\n GetDisplaysResponse,\n ApiError,\n TableData,\n} from \"./types\";\nimport { readParquet } from \"./parquet\";\n\n/**\n * Oxy API Client for interacting with Oxy data\n */\nexport class OxyClient {\n private config: OxyConfig;\n\n constructor(config: OxyConfig) {\n this.config = config;\n }\n\n /**\n * Creates an OxyClient instance asynchronously with support for postMessage authentication\n *\n * This is the recommended method when using the SDK in an iframe that needs to\n * obtain authentication from the parent window via postMessage.\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxyClient instance\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const client = await OxyClient.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n *\n * // Use the client normally\n * const apps = await client.listApps();\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxyClient> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxyClient(resolvedConfig);\n }\n\n /**\n * Encodes a file path to base64 for use in API URLs\n */\n private encodePathBase64(path: string): string {\n if (typeof Buffer !== \"undefined\") {\n // Node.js environment\n return Buffer.from(path).toString(\"base64\");\n } else {\n // Browser environment\n return btoa(path);\n }\n }\n\n /**\n * Makes an authenticated HTTP request to the Oxy API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...((options.headers as Record<string, string>) || {}),\n };\n\n // Only add Authorization header if API key is provided (optional for local dev)\n if (this.config.apiKey) {\n headers[\"Authorization\"] = `Bearer ${this.config.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.timeout || 30000,\n );\n\n try {\n const response = await fetch(url, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n const error: ApiError = {\n message: `API request failed: ${response.statusText}`,\n status: response.status,\n details: errorText,\n };\n throw error;\n }\n\n // Handle binary responses\n const acceptHeader =\n typeof options.headers === \"object\" && options.headers !== null\n ? (options.headers as Record<string, string>)[\"Accept\"]\n : undefined;\n if (acceptHeader === \"application/octet-stream\") {\n return response.blob() as Promise<T>;\n }\n\n return response.json();\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\n `Request timeout after ${this.config.timeout || 30000}ms`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Builds query parameters including optional branch\n */\n private buildQueryParams(\n additionalParams: Record<string, string> = {},\n ): string {\n const params: Record<string, string> = { ...additionalParams };\n\n if (this.config.branch) {\n params.branch = this.config.branch;\n }\n\n const searchParams = new URLSearchParams(params);\n const queryString = searchParams.toString();\n return queryString ? `?${queryString}` : \"\";\n }\n\n /**\n * Lists all apps in the project\n *\n * @returns Array of app items\n *\n * @example\n * ```typescript\n * const apps = await client.listApps();\n * console.log('Available apps:', apps);\n * ```\n */\n async listApps(): Promise<AppItem[]> {\n const query = this.buildQueryParams();\n return this.request<AppItem[]>(`/${this.config.projectId}/app${query}`);\n }\n\n /**\n * Gets data for a specific app\n *\n * @param appPath - Relative path to the app file (e.g., 'my-app.app.yml')\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.getAppData('dashboard.app.yml');\n * if (data.error) {\n * console.error('Error:', data.error);\n * } else {\n * console.log('App data:', data.data);\n * }\n * ```\n */\n async getAppData(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}${query}`,\n );\n }\n\n /**\n * Runs an app and returns fresh data (bypasses cache)\n *\n * @param appPath - Relative path to the app file\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.runApp('dashboard.app.yml');\n * console.log('Fresh app data:', data.data);\n * ```\n */\n async runApp(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}/run${query}`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Gets display configurations for an app\n *\n * @param appPath - Relative path to the app file\n * @returns Display configurations with potential errors\n *\n * @example\n * ```typescript\n * const displays = await client.getDisplays('dashboard.app.yml');\n * displays.displays.forEach(d => {\n * if (d.error) {\n * console.error('Display error:', d.error);\n * } else {\n * console.log('Display:', d.display);\n * }\n * });\n * ```\n */\n async getDisplays(appPath: string): Promise<GetDisplaysResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<GetDisplaysResponse>(\n `/${this.config.projectId}/app/${pathb64}/displays${query}`,\n );\n }\n\n /**\n * Gets a file from the app state directory (e.g., generated charts, images)\n *\n * This is useful for retrieving generated assets like charts, images, or other\n * files produced by app workflows and stored in the state directory.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Blob containing the file data\n *\n * @example\n * ```typescript\n * // Get a generated chart image\n * const blob = await client.getFile('charts/sales-chart.png');\n * const imageUrl = URL.createObjectURL(blob);\n *\n * // Use in an img tag\n * document.querySelector('img').src = imageUrl;\n * ```\n *\n * @example\n * ```typescript\n * // Download a file\n * const blob = await client.getFile('exports/data.csv');\n * const a = document.createElement('a');\n * a.href = URL.createObjectURL(blob);\n * a.download = 'data.csv';\n * a.click();\n * ```\n */\n async getFile(filePath: string): Promise<Blob> {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return this.request<Blob>(\n `/${this.config.projectId}/app/file/${pathb64}${query}`,\n {\n headers: {\n Accept: \"application/octet-stream\",\n },\n },\n );\n }\n\n /**\n * Gets a file URL for direct browser access\n *\n * This returns a URL that can be used directly in img tags, fetch calls, etc.\n * The URL includes authentication via query parameters.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Full URL to the file\n *\n * @example\n * ```typescript\n * const imageUrl = client.getFileUrl('charts/sales-chart.png');\n *\n * // Use directly in img tag (in environments where query-based auth is supported)\n * document.querySelector('img').src = imageUrl;\n * ```\n */\n getFileUrl(filePath: string): string {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return `${this.config.baseUrl}/${this.config.projectId}/app/file/${pathb64}${query}`;\n }\n\n /**\n * Fetches a parquet file and parses it into table data\n *\n * @param filePath - Relative path to the parquet file\n * @param limit - Maximum number of rows to return (default: 100)\n * @returns TableData with columns and rows\n *\n * @example\n * ```typescript\n * const tableData = await client.getTableData('data/sales.parquet', 50);\n * console.log(tableData.columns);\n * console.log(tableData.rows);\n * console.log(`Total rows: ${tableData.total_rows}`);\n * ```\n */\n async getTableData(\n filePath: string,\n limit: number = 100,\n ): Promise<TableData> {\n const blob = await this.getFile(filePath);\n const result = await readParquet(blob, \"data\", limit);\n\n return {\n columns: result.columns,\n rows: result.rows,\n total_rows: result.rowCount,\n };\n }\n}\n","import { OxyClient } from \"./client\";\nimport { OxyConfig, createConfigAsync } from \"./config\";\nimport { ParquetReader, QueryResult } from \"./parquet\";\nimport { DataContainer } from \"./types\";\n\n/**\n * OxySDK provides a unified interface for fetching data from Oxy and querying it with SQL.\n * It combines OxyClient (for API calls) and ParquetReader (for SQL queries) into a single,\n * easy-to-use interface.\n *\n * @example\n * ```typescript\n * // Create SDK instance\n * const sdk = new OxySDK({ apiKey: 'your-key', projectId: 'your-project' });\n *\n * // Load a parquet file and query it\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales WHERE amount > 1000');\n * console.log(result.rows);\n *\n * // Clean up when done\n * await sdk.close();\n * ```\n */\nexport class OxySDK {\n private client: OxyClient;\n private reader: ParquetReader;\n\n constructor(config: OxyConfig) {\n this.client = new OxyClient(config);\n this.reader = new ParquetReader();\n }\n\n /**\n * Creates an OxySDK instance asynchronously with support for postMessage authentication\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxySDK instance\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const sdk = await OxySDK.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id'\n * });\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxySDK> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxySDK(resolvedConfig);\n }\n\n /**\n * Load a Parquet file from Oxy and register it for SQL queries\n *\n * @param filePath - Path to the parquet file in the app state directory\n * @param tableName - Name to use for the table in SQL queries\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * await sdk.loadFile('data/customers.parquet', 'customers');\n *\n * const result = await sdk.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async loadFile(filePath: string, tableName: string): Promise<void> {\n const blob = await this.client.getFile(filePath);\n await this.reader.registerParquet(blob, tableName);\n }\n\n /**\n * Load multiple Parquet files at once\n *\n * @param files - Array of file paths and table names\n *\n * @example\n * ```typescript\n * await sdk.loadFiles([\n * { filePath: 'data/sales.parquet', tableName: 'sales' },\n * { filePath: 'data/customers.parquet', tableName: 'customers' },\n * { filePath: 'data/products.parquet', tableName: 'products' }\n * ]);\n *\n * const result = await sdk.query('SELECT * FROM sales');\n * ```\n */\n async loadFiles(\n files: Array<{ filePath: string; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.loadFile(file.filePath, file.tableName);\n }\n }\n\n /**\n * Load all data from an app's data container\n *\n * This fetches the app's data and registers all parquet files using their container keys as table names.\n *\n * @param appPath - Path to the app file\n * @returns DataContainer with file references\n *\n * @example\n * ```typescript\n * // If app has data: { sales: { file_path: 'data/sales.parquet' } }\n * const data = await sdk.loadAppData('dashboard.app.yml');\n * // Now you can query the 'sales' table\n * const result = await sdk.query('SELECT * FROM sales LIMIT 10');\n * ```\n */\n async loadAppData(appPath: string): Promise<DataContainer | null> {\n const appDataResponse = await this.client.getAppData(appPath);\n\n if (appDataResponse.error) {\n throw new Error(`Failed to load app data: ${appDataResponse.error}`);\n }\n\n if (!appDataResponse.data) {\n return null;\n }\n\n // Load each file in the data container\n const loadPromises = Object.entries(appDataResponse.data).map(\n async ([tableName, fileRef]) => {\n await this.loadFile(fileRef.file_path, tableName);\n },\n );\n\n await Promise.all(loadPromises);\n\n return appDataResponse.data;\n }\n\n /**\n * Execute a SQL query against loaded data\n *\n * @param sql - SQL query to execute\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n *\n * const result = await sdk.query('SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result.columns); // ['product', 'total']\n * console.log(result.rows); // [['Product A', 1000], ['Product B', 2000]]\n * console.log(result.rowCount); // 2\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n return this.reader.query(sql);\n }\n\n /**\n * Get all data from a loaded table\n *\n * @param tableName - Name of the table\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const allData = await sdk.getAll('sales');\n * const first100 = await sdk.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n return this.reader.getAll(tableName, limit);\n }\n\n /**\n * Get schema information for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Schema information\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const schema = await sdk.getSchema('sales');\n * console.log(schema.columns); // ['column_name', 'column_type', ...]\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.reader.getSchema(tableName);\n }\n\n /**\n * Get row count for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Number of rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const count = await sdk.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n return this.reader.count(tableName);\n }\n\n /**\n * Get direct access to the underlying OxyClient\n *\n * Useful for advanced operations like listing apps, getting displays, etc.\n *\n * @returns The OxyClient instance\n *\n * @example\n * ```typescript\n * const apps = await sdk.getClient().listApps();\n * const displays = await sdk.getClient().getDisplays('my-app.app.yml');\n * ```\n */\n getClient(): OxyClient {\n return this.client;\n }\n\n /**\n * Get direct access to the underlying ParquetReader\n *\n * Useful for advanced operations like registering blobs directly.\n *\n * @returns The ParquetReader instance\n *\n * @example\n * ```typescript\n * const myBlob = new Blob([parquetData]);\n * await sdk.getReader().registerParquet(myBlob, 'mydata');\n * ```\n */\n getReader(): ParquetReader {\n return this.reader;\n }\n\n /**\n * Close and cleanup all resources\n *\n * This clears all loaded data and releases resources. Call this when you're done with the SDK.\n *\n * @example\n * ```typescript\n * const sdk = new OxySDK({ apiKey: 'key', projectId: 'project' });\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales');\n * await sdk.close(); // Clean up\n * ```\n */\n async close(): Promise<void> {\n await this.reader.close();\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n ReactNode,\n} from \"react\";\nimport { OxySDK } from \"./sdk\";\nimport { OxyConfig } from \"./config\";\n\n/**\n * Context value provided to child components\n */\nexport interface OxyContextValue {\n sdk: OxySDK | null;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * React context for OxySDK\n */\nconst OxyContext = createContext<OxyContextValue | undefined>(undefined);\n\n/**\n * Props for OxyProvider component\n */\nexport interface OxyProviderProps {\n children: ReactNode;\n config?: Partial<OxyConfig>;\n /**\n * If true, uses async initialization (supports postMessage auth in iframes)\n * If false, uses synchronous initialization with provided config\n */\n useAsync?: boolean;\n /**\n * Optional app path to load initial app data from upon initialization\n */\n appPath?: string;\n /**\n * Optional initial files to preload into the SDK as a mapping of filename to content\n */\n files?: Record<string, string>;\n /**\n * Called when SDK is successfully initialized\n */\n onReady?: (sdk: OxySDK) => void;\n /**\n * Called when initialization fails\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Provider component that initializes and provides OxySDK to child components\n *\n * @example\n * ```tsx\n * // Synchronous initialization with config\n * function App() {\n * return (\n * <OxyProvider config={{\n * apiKey: 'your-key',\n * projectId: 'your-project',\n * baseUrl: 'https://api.oxy.tech'\n * }}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Async initialization (for iframe/postMessage auth)\n * function App() {\n * return (\n * <OxyProvider\n * useAsync\n * config={{ parentOrigin: 'https://app.example.com' }}\n * >\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With environment variables\n * import { createConfig } from '@oxy/sdk';\n *\n * function App() {\n * return (\n * <OxyProvider config={createConfig()}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n */\nexport function OxyProvider({\n children,\n config,\n useAsync = false,\n appPath,\n files,\n onReady,\n onError,\n}: OxyProviderProps) {\n const [sdk, setSdk] = useState<OxySDK | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n let sdkInstance: OxySDK | null = null;\n\n async function initializeSDK() {\n try {\n setIsLoading(true);\n setError(null);\n\n if (useAsync) {\n // Async initialization (supports postMessage auth)\n sdkInstance = await OxySDK.create(config);\n if (appPath) {\n await sdkInstance.loadAppData(appPath);\n }\n\n if (files) {\n const fileEntries = Object.entries(files).map(\n ([tableName, filePath]) => ({\n tableName,\n filePath,\n }),\n );\n await sdkInstance.loadFiles(fileEntries);\n }\n } else {\n // Sync initialization with provided config\n if (!config) {\n throw new Error(\n \"Config is required when useAsync is false. Either provide config or set useAsync=true.\",\n );\n }\n sdkInstance = new OxySDK(config as OxyConfig);\n }\n\n if (mounted) {\n setSdk(sdkInstance);\n setIsLoading(false);\n onReady?.(sdkInstance);\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Failed to initialize SDK\");\n\n if (mounted) {\n setError(error);\n setIsLoading(false);\n onError?.(error);\n }\n }\n }\n\n initializeSDK();\n\n // Cleanup function\n return () => {\n mounted = false;\n if (sdkInstance) {\n sdkInstance.close().catch(console.error);\n }\n };\n }, [config, useAsync, onReady, onError]);\n\n return (\n <OxyContext.Provider value={{ sdk, isLoading, error }}>\n {children}\n </OxyContext.Provider>\n );\n}\n\n/**\n * Hook to access OxySDK from child components\n *\n * @throws {Error} If used outside of OxyProvider\n * @returns {OxyContextValue} The SDK instance, loading state, and error\n *\n * @example\n * ```tsx\n * function Dashboard() {\n * const { sdk, isLoading, error } = useOxy();\n *\n * useEffect(() => {\n * if (sdk) {\n * sdk.loadAppData('dashboard.app.yml')\n * .then(() => sdk.query('SELECT * FROM my_table'))\n * .then(result => console.log(result));\n * }\n * }, [sdk]);\n *\n * if (isLoading) return <div>Loading SDK...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!sdk) return null;\n *\n * return <div>Dashboard</div>;\n * }\n * ```\n */\nexport function useOxy(): OxyContextValue {\n const context = useContext(OxyContext);\n\n if (context === undefined) {\n throw new Error(\"useOxy must be used within an OxyProvider\");\n }\n\n return context;\n}\n\n/**\n * Hook to access OxySDK that throws if not ready\n *\n * This is a convenience hook that returns the SDK directly or throws an error if not initialized.\n * Use this when you know the SDK should be ready.\n *\n * @throws {Error} If used outside of OxyProvider or if SDK is not initialized\n * @returns {OxySDK} The SDK instance\n *\n * @example\n * ```tsx\n * function DataTable() {\n * const sdk = useOxySDK();\n * const [data, setData] = useState(null);\n *\n * useEffect(() => {\n * sdk.loadFile('data.parquet', 'data')\n * .then(() => sdk.query('SELECT * FROM data LIMIT 100'))\n * .then(setData);\n * }, [sdk]);\n *\n * return <table>...</table>;\n * }\n * ```\n */\nexport function useOxySDK(): OxySDK {\n const { sdk, isLoading, error } = useOxy();\n\n if (error) {\n throw error;\n }\n\n if (isLoading || !sdk) {\n throw new Error(\"OxySDK is not yet initialized\");\n }\n\n return sdk;\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -775,6 +775,14 @@ interface OxyProviderProps {
|
|
|
775
775
|
* If false, uses synchronous initialization with provided config
|
|
776
776
|
*/
|
|
777
777
|
useAsync?: boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Optional app path to load initial app data from upon initialization
|
|
780
|
+
*/
|
|
781
|
+
appPath?: string;
|
|
782
|
+
/**
|
|
783
|
+
* Optional initial files to preload into the SDK as a mapping of filename to content
|
|
784
|
+
*/
|
|
785
|
+
files?: Record<string, string>;
|
|
778
786
|
/**
|
|
779
787
|
* Called when SDK is successfully initialized
|
|
780
788
|
*/
|
|
@@ -836,6 +844,8 @@ declare function OxyProvider({
|
|
|
836
844
|
children,
|
|
837
845
|
config,
|
|
838
846
|
useAsync,
|
|
847
|
+
appPath,
|
|
848
|
+
files,
|
|
839
849
|
onReady,
|
|
840
850
|
onError
|
|
841
851
|
}: OxyProviderProps): React.JSX.Element;
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/config.ts","../src/types.ts","../src/client.ts","../src/parquet.ts","../src/sdk.ts","../src/react.tsx","../src/auth/postMessage.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAGiB,SAAA;EAAA;AA4EjB;;EAAyC,OAAA,EAAA,MAAA;EAAqB;;AA6D9D;EACsB,MAAA,CAAA,EAAA,MAAA;EAAR;;;EACJ,SAAA,EAAA,MAAA;;;;EC3IO,MAAA,CAAA,EAAA,MAAO;EAQP;AAQjB;AAMA;EAKiB,OAAA,CAAA,EAAA,MAAA;EAQA;AAQjB;AAQA;AAoBA;AAUA;AAYA;EAYiB,YAAA,CAAA,EAAA,MAAA;EAcJ;AAoBb;AAeA;AA0BA;;;;AC1KA;;;;;;;;;;;;AAoN8C,iBFlJ9B,YAAA,CEkJ8B,SAAA,CAAA,EFlJL,OEkJK,CFlJG,SEkJH,CAAA,CAAA,EFlJgB,SEkJhB;;;;;;;;;;ACtM9C;AA0CA;AAUA;;;;;;;;;;;;;;;AA2QA;;;;;AA+BA;;AAIW,iBHjPW,iBAAA,CGiPX,SAAA,CAAA,EHhPG,OGgPH,CHhPW,SGgPX,CAAA,CAAA,EH/OR,OG+OQ,CH/OA,SG+OA,CAAA;;;;;;UF1XM,OAAA;EDAA,IAAA,EAAA,MAAS;EA4EV,IAAA,EAAA,MAAA;;;;;AA6DM,UCjIL,aAAA,CDiIsB;EACjB,SAAA,EAAA,MAAA;;;;;;UC1HL,SAAA;;EAhBA,IAAA,EAAA,OAAO,EAAA,EAAA;EAQP,UAAA,CAAA,EAAA,MAAa;AAQ9B;AAMY,KAAA,aAAA,GAAgB,MAAe,CAAA,MAAA,EAAA,aAAT,CAAA;AAKlC;AAQA;AAQA;AAQiB,UAxBA,eAAA,CAwBmB;EAoBnB,IAAA,EA3CT,aA2CS,GAAA,IAAqB;EAUrB,KAAA,EAAA,MAAA,GAAA,IAAA;AAYjB;AAYA;AAcA;AAoBA;AAea,UAvHI,gBAAA,CAuHJ;EA0BA,OAAA,CAAA,EAhJD,WAgJC;;;;AC1Kb;;AA+BuC,UDEtB,WAAA,CCFsB;EAAR,IAAA,EAAA,MAAA;EAA6B,OAAA,EAAA,OAAA;;;;;AAsIvB,UD5HpB,mBAAA,CC4HoB;EAoBI,QAAA,ED/I7B,gBC+I6B,EAAA;;;;AC3KzC;AA0CA;AAUA;;AAwCwD,UF7CvC,qBAAA,CE6CuC;EAmD/B,IAAA,EAAA,kBAAA;EAAd,OAAA,EAAA,KAAA;EACN,SAAA,EAAA,MAAA;EA+B+B,SAAA,EAAA,MAAA;;;;;AAyEE,UF/LrB,sBAAA,CE+LqB;EAgBJ,IAAA,EAAA,mBAAA;EAUjB,OAAA,EAAA,KAAA;EAAO,SAAA,EAAA,MAAA;EA6CF,MAAA,CAAA,EAAA,MAAY;EAC1B,SAAA,CAAA,EAAA,MAAA;EAGG,OAAA,CAAA,EAAA,MAAA;;;AA2BX;;AAIW,UF7RM,sBAAA,CE6RN;EAAR;EAAO,YAAA,CAAA,EAAA,MAAA;;;;ECrWG,OAAA,CAAA,EAAM,MAAA;;;;;AAwBiC,UH4DnC,qBAAA,CG5DmC;EAuBG,MAAA,CAAA,EAAA,MAAA;EAsB5C,SAAA,CAAA,EAAA,MAAA;EACN,OAAA,CAAA,EAAA,MAAA;EAsByC,MAAA,EAAA,aAAA;;;;;;;;AA4FZ,cHtFrB,2BAAA,SAAoC,KAAA,CGsFf;EAiBnB,WAAA,CAAA,OAAA,EAAA,MAAA;;;;;cHnFF,iCAAA,SAA0C,KAAA;;AIjIvD;AAcA;;;AAEW,cJgIE,+BAAA,SAAwC,KAAA,CIhI1C;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/config.ts","../src/types.ts","../src/client.ts","../src/parquet.ts","../src/sdk.ts","../src/react.tsx","../src/auth/postMessage.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -775,6 +775,14 @@ interface OxyProviderProps {
|
|
|
775
775
|
* If false, uses synchronous initialization with provided config
|
|
776
776
|
*/
|
|
777
777
|
useAsync?: boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Optional app path to load initial app data from upon initialization
|
|
780
|
+
*/
|
|
781
|
+
appPath?: string;
|
|
782
|
+
/**
|
|
783
|
+
* Optional initial files to preload into the SDK as a mapping of filename to content
|
|
784
|
+
*/
|
|
785
|
+
files?: Record<string, string>;
|
|
778
786
|
/**
|
|
779
787
|
* Called when SDK is successfully initialized
|
|
780
788
|
*/
|
|
@@ -836,6 +844,8 @@ declare function OxyProvider({
|
|
|
836
844
|
children,
|
|
837
845
|
config,
|
|
838
846
|
useAsync,
|
|
847
|
+
appPath,
|
|
848
|
+
files,
|
|
839
849
|
onReady,
|
|
840
850
|
onError
|
|
841
851
|
}: OxyProviderProps): React.JSX.Element;
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/types.ts","../src/client.ts","../src/parquet.ts","../src/sdk.ts","../src/react.tsx","../src/auth/postMessage.ts"],"sourcesContent":[],"mappings":";;;;;;;;UAGiB,SAAA;EAAA;AA4EjB;;EAAyC,OAAA,EAAA,MAAA;EAAqB;;AA6D9D;EACsB,MAAA,CAAA,EAAA,MAAA;EAAR;;;EACJ,SAAA,EAAA,MAAA;;;;EC3IO,MAAA,CAAA,EAAA,MAAO;EAQP;AAQjB;AAMA;EAKiB,OAAA,CAAA,EAAA,MAAA;EAQA;AAQjB;AAQA;AAoBA;AAUA;AAYA;EAYiB,YAAA,CAAA,EAAA,MAAA;EAcJ;AAoBb;AAeA;AA0BA;;;;AC1KA;;;;;;;;;;;;AAoN8C,iBFlJ9B,YAAA,CEkJ8B,SAAA,CAAA,EFlJL,OEkJK,CFlJG,SEkJH,CAAA,CAAA,EFlJgB,SEkJhB;;;;;;;;;;ACtM9C;AA0CA;AAUA;;;;;;;;;;;;;;;AA2QA;;;;;AA+BA;;AAIW,iBHjPW,iBAAA,CGiPX,SAAA,CAAA,EHhPG,OGgPH,CHhPW,SGgPX,CAAA,CAAA,EH/OR,OG+OQ,CH/OA,SG+OA,CAAA;;;;;;UF1XM,OAAA;EDAA,IAAA,EAAA,MAAS;EA4EV,IAAA,EAAA,MAAA;;;;;AA6DM,UCjIL,aAAA,CDiIsB;EACjB,SAAA,EAAA,MAAA;;;;;;UC1HL,SAAA;;EAhBA,IAAA,EAAA,OAAO,EAAA,EAAA;EAQP,UAAA,CAAA,EAAA,MAAa;AAQ9B;AAMY,KAAA,aAAA,GAAgB,MAAe,CAAA,MAAA,EAAA,aAAT,CAAA;AAKlC;AAQA;AAQA;AAQiB,UAxBA,eAAA,CAwBmB;EAoBnB,IAAA,EA3CT,aA2CS,GAAA,IAAqB;EAUrB,KAAA,EAAA,MAAA,GAAA,IAAA;AAYjB;AAYA;AAcA;AAoBA;AAea,UAvHI,gBAAA,CAuHJ;EA0BA,OAAA,CAAA,EAhJD,WAgJC;;;;AC1Kb;;AA+BuC,UDEtB,WAAA,CCFsB;EAAR,IAAA,EAAA,MAAA;EAA6B,OAAA,EAAA,OAAA;;;;;AAsIvB,UD5HpB,mBAAA,CC4HoB;EAoBI,QAAA,ED/I7B,gBC+I6B,EAAA;;;;AC3KzC;AA0CA;AAUA;;AAwCwD,UF7CvC,qBAAA,CE6CuC;EAmD/B,IAAA,EAAA,kBAAA;EAAd,OAAA,EAAA,KAAA;EACN,SAAA,EAAA,MAAA;EA+B+B,SAAA,EAAA,MAAA;;;;;AAyEE,UF/LrB,sBAAA,CE+LqB;EAgBJ,IAAA,EAAA,mBAAA;EAUjB,OAAA,EAAA,KAAA;EAAO,SAAA,EAAA,MAAA;EA6CF,MAAA,CAAA,EAAA,MAAY;EAC1B,SAAA,CAAA,EAAA,MAAA;EAGG,OAAA,CAAA,EAAA,MAAA;;;AA2BX;;AAIW,UF7RM,sBAAA,CE6RN;EAAR;EAAO,YAAA,CAAA,EAAA,MAAA;;;;ECrWG,OAAA,CAAA,EAAM,MAAA;;;;;AAwBiC,UH4DnC,qBAAA,CG5DmC;EAuBG,MAAA,CAAA,EAAA,MAAA;EAsB5C,SAAA,CAAA,EAAA,MAAA;EACN,OAAA,CAAA,EAAA,MAAA;EAsByC,MAAA,EAAA,aAAA;;;;;;;;AA4FZ,cHtFrB,2BAAA,SAAoC,KAAA,CGsFf;EAiBnB,WAAA,CAAA,OAAA,EAAA,MAAA;;;;;cHnFF,iCAAA,SAA0C,KAAA;;AIjIvD;AAcA;;;AAEW,cJgIE,+BAAA,SAAwC,KAAA,CIhI1C;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/config.ts","../src/types.ts","../src/client.ts","../src/parquet.ts","../src/sdk.ts","../src/react.tsx","../src/auth/postMessage.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -921,7 +921,7 @@ const OxyContext = createContext(void 0);
|
|
|
921
921
|
* }
|
|
922
922
|
* ```
|
|
923
923
|
*/
|
|
924
|
-
function OxyProvider({ children, config, useAsync = false, onReady, onError }) {
|
|
924
|
+
function OxyProvider({ children, config, useAsync = false, appPath, files, onReady, onError }) {
|
|
925
925
|
const [sdk, setSdk] = useState(null);
|
|
926
926
|
const [isLoading, setIsLoading] = useState(true);
|
|
927
927
|
const [error, setError] = useState(null);
|
|
@@ -932,8 +932,17 @@ function OxyProvider({ children, config, useAsync = false, onReady, onError }) {
|
|
|
932
932
|
try {
|
|
933
933
|
setIsLoading(true);
|
|
934
934
|
setError(null);
|
|
935
|
-
if (useAsync)
|
|
936
|
-
|
|
935
|
+
if (useAsync) {
|
|
936
|
+
sdkInstance = await OxySDK.create(config);
|
|
937
|
+
if (appPath) await sdkInstance.loadAppData(appPath);
|
|
938
|
+
if (files) {
|
|
939
|
+
const fileEntries = Object.entries(files).map(([tableName, filePath]) => ({
|
|
940
|
+
tableName,
|
|
941
|
+
filePath
|
|
942
|
+
}));
|
|
943
|
+
await sdkInstance.loadFiles(fileEntries);
|
|
944
|
+
}
|
|
945
|
+
} else {
|
|
937
946
|
if (!config) throw new Error("Config is required when useAsync is false. Either provide config or set useAsync=true.");
|
|
938
947
|
sdkInstance = new OxySDK(config);
|
|
939
948
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["isInIframe","requestAuthFromParent","error"],"sources":["../src/config.ts","../src/parquet.ts","../src/client.ts","../src/sdk.ts","../src/react.tsx"],"sourcesContent":["/**\n * Configuration for the Oxy SDK\n */\nexport interface OxyConfig {\n /**\n * Base URL of the Oxy API (e.g., 'https://api.oxy.tech' or 'http://localhost:3000')\n */\n baseUrl: string;\n\n /**\n * API key for authentication (optional for local development)\n */\n apiKey?: string;\n\n /**\n * Project ID (UUID)\n */\n projectId: string;\n\n /**\n * Optional branch name (defaults to current branch if not specified)\n */\n branch?: string;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Parent window origin for postMessage authentication (iframe scenarios)\n * Required when using postMessage auth for security.\n * Example: 'https://app.example.com'\n * Use '*' only in development!\n */\n parentOrigin?: string;\n\n /**\n * Disable automatic postMessage authentication even if in iframe\n * Set to true if you want to provide API key manually in iframe context\n */\n disableAutoAuth?: boolean;\n}\n\n/**\n * Safely get environment variable in both Node.js and browser environments\n */\nfunction getEnvVar(name: string): string | undefined {\n // Check if we're in Node.js\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n\n // Check if we're in a Vite environment (browser)\n if (typeof import.meta !== 'undefined' && (import.meta as any).env) {\n // Try with VITE_ prefix first (Vite convention)\n const viteValue = (import.meta as any).env[`VITE_${name}`];\n if (viteValue !== undefined) return viteValue;\n\n // Try without prefix\n return (import.meta as any).env[name];\n }\n\n return undefined;\n}\n\n/**\n * Creates an Oxy configuration from environment variables\n *\n * Environment variables:\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns OxyConfig object\n * @throws Error if required environment variables are missing\n */\nexport function createConfig(overrides?: Partial<OxyConfig>): OxyConfig {\n const baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n const apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n const projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n\n/**\n * Creates an Oxy configuration asynchronously with support for postMessage authentication\n *\n * This is the recommended method for iframe scenarios where authentication\n * needs to be obtained from the parent window via postMessage.\n *\n * When running in an iframe without an API key, this function will:\n * 1. Detect the iframe context\n * 2. Send an authentication request to the parent window\n * 3. Wait for the parent to respond with credentials\n * 4. Return the configured client\n *\n * Environment variables (fallback):\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns Promise resolving to OxyConfig object\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // Automatic iframe detection and authentication\n * const config = await createConfigAsync({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n * ```\n */\nexport async function createConfigAsync(\n overrides?: Partial<OxyConfig>,\n): Promise<OxyConfig> {\n // Import postMessage utilities (dynamic to avoid circular deps)\n const { isInIframe } = await import(\"./auth/postMessage\");\n\n // Start with environment variables and overrides\n let baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n let apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n let projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n const disableAutoAuth = overrides?.disableAutoAuth ?? false;\n const parentOrigin = overrides?.parentOrigin;\n\n // Automatic iframe detection and authentication\n if (!disableAutoAuth && isInIframe() && !apiKey) {\n if (!parentOrigin) {\n logWarningAboutMissingParentOrigin();\n } else {\n apiKey = await attemptPostMessageAuth(\n parentOrigin,\n overrides?.timeout || 5000,\n apiKey,\n projectId,\n baseUrl,\n )\n .then((result) => {\n if (result.projectId) projectId = result.projectId;\n if (result.baseUrl) baseUrl = result.baseUrl;\n return result.apiKey;\n })\n .catch((error) => {\n console.error(\n \"[Oxy SDK] Failed to authenticate via postMessage:\",\n (error as Error).message,\n );\n return apiKey;\n });\n }\n }\n\n return createFinalConfig(baseUrl, apiKey, projectId, overrides);\n}\n\nfunction logWarningAboutMissingParentOrigin(): void {\n console.warn(\n \"[Oxy SDK] Running in iframe without API key and no parentOrigin specified. \" +\n \"PostMessage authentication will be skipped. \" +\n \"Provide parentOrigin config to enable automatic authentication.\",\n );\n}\n\nasync function attemptPostMessageAuth(\n parentOrigin: string,\n timeout: number,\n currentApiKey: string | undefined,\n currentProjectId: string | undefined,\n currentBaseUrl: string | undefined,\n): Promise<{ apiKey?: string; projectId?: string; baseUrl?: string }> {\n const { requestAuthFromParent } = await import(\"./auth/postMessage\");\n const authResult = await requestAuthFromParent({ parentOrigin, timeout });\n\n console.log(\"[Oxy SDK] Successfully authenticated via postMessage\");\n\n return {\n apiKey: authResult.apiKey || currentApiKey,\n projectId: authResult.projectId || currentProjectId,\n baseUrl: authResult.baseUrl || currentBaseUrl,\n };\n}\n\nfunction createFinalConfig(\n baseUrl: string | undefined,\n apiKey: string | undefined,\n projectId: string | undefined,\n overrides?: Partial<OxyConfig>,\n): OxyConfig {\n // Validation\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n","import * as duckdb from \"@duckdb/duckdb-wasm\";\n\nlet dbInstance: duckdb.AsyncDuckDB | null = null;\nlet connection: duckdb.AsyncDuckDBConnection | null = null;\n\n// Queue to serialize operations and prevent race conditions\nlet operationQueue = Promise.resolve();\n\n/**\n * Enqueue an operation to prevent race conditions on shared DuckDB instance\n */\nfunction enqueueOperation<T>(operation: () => Promise<T>): Promise<T> {\n const currentOperation = operationQueue.then(operation, operation);\n operationQueue = currentOperation.then(\n () => {\n return;\n },\n () => {\n return;\n },\n );\n return currentOperation;\n}\n\n/**\n * Initialize DuckDB-WASM instance\n */\nexport async function initializeDuckDB(): Promise<duckdb.AsyncDuckDB> {\n if (dbInstance) {\n return dbInstance;\n }\n\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();\n\n // Select a bundle based on browser features\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);\n\n const worker_url = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], {\n type: \"text/javascript\",\n }),\n );\n\n const worker = new Worker(worker_url);\n const logger = new duckdb.ConsoleLogger();\n\n dbInstance = new duckdb.AsyncDuckDB(logger, worker);\n await dbInstance.instantiate(bundle.mainModule, bundle.pthreadWorker);\n URL.revokeObjectURL(worker_url);\n\n return dbInstance;\n}\n\n/**\n * Get or create a DuckDB connection\n */\nasync function getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (connection) {\n return connection;\n }\n\n const db = await initializeDuckDB();\n connection = await db.connect();\n return connection;\n}\n\n/**\n * Query result interface\n */\nexport interface QueryResult {\n columns: string[];\n rows: unknown[][];\n rowCount: number;\n}\n\n/**\n * ParquetReader provides methods to read and query Parquet files.\n * Supports registering multiple Parquet files with different table names.\n */\nexport class ParquetReader {\n private tableMap: Map<string, string> = new Map(); // Maps user table name -> internal unique table name\n\n constructor() {\n // No default table name - all tables must be explicitly named\n }\n\n /**\n * Generate a unique internal table name to prevent conflicts\n */\n private generateInternalTableName(tableName: string): string {\n // Note: Math.random() is acceptable here as uniqueness is only needed for table naming (not security-critical)\n /* eslint-disable sonarjs/pseudo-random */\n const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n /* eslint-enable sonarjs/pseudo-random */\n return `${tableName}_${uniqueId}`;\n }\n\n /**\n * Register a Parquet file from a Blob with a specific table name\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (required)\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const reader = new ParquetReader();\n * await reader.registerParquet(blob, 'sales');\n * ```\n *\n * @example\n * ```typescript\n * // Register multiple files\n * const reader = new ParquetReader();\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerParquet(blob: Blob, tableName: string): Promise<void> {\n const internalTableName = this.generateInternalTableName(tableName);\n\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Convert blob to Uint8Array\n const arrayBuffer = await blob.arrayBuffer();\n const uint8Array = new Uint8Array(arrayBuffer);\n\n // Register the file with DuckDB using unique name\n await db.registerFileBuffer(\n `${internalTableName}.parquet`,\n uint8Array,\n );\n\n // Drop table if it exists\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error if table doesn't exist\n }\n\n // Create table from parquet\n await conn.query(\n `CREATE TABLE ${internalTableName} AS SELECT * FROM '${internalTableName}.parquet'`,\n );\n\n // Store mapping\n this.tableMap.set(tableName, internalTableName);\n });\n }\n\n /**\n * Register multiple Parquet files at once\n *\n * @param files - Array of objects containing blob and tableName\n *\n * @example\n * ```typescript\n * const reader = new ParquetReader();\n * await reader.registerMultipleParquet([\n * { blob: salesBlob, tableName: 'sales' },\n * { blob: customersBlob, tableName: 'customers' },\n * { blob: productsBlob, tableName: 'products' }\n * ]);\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerMultipleParquet(\n files: Array<{ blob: Blob; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.registerParquet(file.blob, file.tableName);\n }\n }\n\n /**\n * Execute a SQL query against the registered Parquet data\n *\n * @param sql - SQL query string\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * const result = await reader.query('SELECT * FROM sales LIMIT 10');\n * console.log(result.columns);\n * console.log(result.rows);\n * ```\n *\n * @example\n * ```typescript\n * // Query multiple tables\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n if (this.tableMap.size === 0) {\n throw new Error(\n \"No Parquet files registered. Call registerParquet() first.\",\n );\n }\n\n return enqueueOperation(async () => {\n const conn = await getConnection();\n\n // Replace all registered table names with their internal unique names\n let rewrittenSql = sql;\n for (const [userTableName, internalTableName] of this.tableMap.entries()) {\n rewrittenSql = rewrittenSql.replace(\n new RegExp(`\\\\b${userTableName}\\\\b`, \"g\"),\n internalTableName,\n );\n }\n\n const result = await conn.query(rewrittenSql);\n\n const columns = result.schema.fields.map((field) => field.name);\n const rows: unknown[][] = [];\n\n // Convert Arrow table to rows\n for (let i = 0; i < result.numRows; i++) {\n const row: unknown[] = [];\n for (let j = 0; j < result.numCols; j++) {\n const col = result.getChildAt(j);\n row.push(col?.get(i));\n }\n rows.push(row);\n }\n\n return {\n columns,\n rows,\n rowCount: result.numRows,\n };\n });\n }\n\n /**\n * Get all data from a registered table\n *\n * @param tableName - Name of the table to query\n * @param limit - Maximum number of rows to return (default: all)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const allData = await reader.getAll('sales');\n * const first100 = await reader.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n const limitClause = limit ? ` LIMIT ${limit}` : \"\";\n return this.query(`SELECT * FROM ${tableName}${limitClause}`);\n }\n\n /**\n * Get table schema information\n *\n * @param tableName - Name of the table to describe\n * @returns Schema information\n *\n * @example\n * ```typescript\n * const schema = await reader.getSchema('sales');\n * console.log(schema.columns); // ['id', 'name', 'sales']\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.query(`DESCRIBE ${tableName}`);\n }\n\n /**\n * Get row count for a table\n *\n * @param tableName - Name of the table to count\n * @returns Number of rows in the table\n *\n * @example\n * ```typescript\n * const count = await reader.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n const result = await this.query(\n `SELECT COUNT(*) as count FROM ${tableName}`,\n );\n return result.rows[0][0] as number;\n }\n\n /**\n * Close and cleanup all registered resources\n */\n async close(): Promise<void> {\n if (this.tableMap.size > 0) {\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Drop all registered tables and file buffers\n for (const [, internalTableName] of this.tableMap.entries()) {\n // Drop the table using internal unique name\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error\n }\n\n // Drop the registered file buffer using internal unique name\n try {\n await db.dropFile(`${internalTableName}.parquet`);\n } catch {\n // Ignore error if file doesn't exist\n }\n }\n\n // Clear the table map\n this.tableMap.clear();\n });\n }\n }\n}\n\n/**\n * Helper function to quickly read a Parquet blob and execute a query\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (default: 'data')\n * @param sql - SQL query to execute (optional, defaults to SELECT * FROM tableName)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const result = await queryParquet(blob, 'sales', 'SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result);\n * ```\n */\nexport async function queryParquet(\n blob: Blob,\n tableName: string = \"data\",\n sql?: string,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const query = sql || `SELECT * FROM ${tableName}`;\n const result = await reader.query(query);\n\n await reader.close();\n return result;\n}\n\n/**\n * Helper function to read Parquet file and get all data\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table (default: 'data')\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const data = await readParquet(blob, 'sales', 1000);\n * console.log(`Loaded ${data.rowCount} rows`);\n * ```\n */\nexport async function readParquet(\n blob: Blob,\n tableName: string = \"data\",\n limit?: number,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const result = await reader.getAll(tableName, limit);\n\n await reader.close();\n return result;\n}\n","import { OxyConfig, createConfigAsync } from \"./config\";\nimport {\n AppItem,\n AppDataResponse,\n GetDisplaysResponse,\n ApiError,\n TableData,\n} from \"./types\";\nimport { readParquet } from \"./parquet\";\n\n/**\n * Oxy API Client for interacting with Oxy data\n */\nexport class OxyClient {\n private config: OxyConfig;\n\n constructor(config: OxyConfig) {\n this.config = config;\n }\n\n /**\n * Creates an OxyClient instance asynchronously with support for postMessage authentication\n *\n * This is the recommended method when using the SDK in an iframe that needs to\n * obtain authentication from the parent window via postMessage.\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxyClient instance\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const client = await OxyClient.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n *\n * // Use the client normally\n * const apps = await client.listApps();\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxyClient> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxyClient(resolvedConfig);\n }\n\n /**\n * Encodes a file path to base64 for use in API URLs\n */\n private encodePathBase64(path: string): string {\n if (typeof Buffer !== \"undefined\") {\n // Node.js environment\n return Buffer.from(path).toString(\"base64\");\n } else {\n // Browser environment\n return btoa(path);\n }\n }\n\n /**\n * Makes an authenticated HTTP request to the Oxy API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...((options.headers as Record<string, string>) || {}),\n };\n\n // Only add Authorization header if API key is provided (optional for local dev)\n if (this.config.apiKey) {\n headers[\"Authorization\"] = `Bearer ${this.config.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.timeout || 30000,\n );\n\n try {\n const response = await fetch(url, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n const error: ApiError = {\n message: `API request failed: ${response.statusText}`,\n status: response.status,\n details: errorText,\n };\n throw error;\n }\n\n // Handle binary responses\n const acceptHeader =\n typeof options.headers === \"object\" && options.headers !== null\n ? (options.headers as Record<string, string>)[\"Accept\"]\n : undefined;\n if (acceptHeader === \"application/octet-stream\") {\n return response.blob() as Promise<T>;\n }\n\n return response.json();\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\n `Request timeout after ${this.config.timeout || 30000}ms`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Builds query parameters including optional branch\n */\n private buildQueryParams(\n additionalParams: Record<string, string> = {},\n ): string {\n const params: Record<string, string> = { ...additionalParams };\n\n if (this.config.branch) {\n params.branch = this.config.branch;\n }\n\n const searchParams = new URLSearchParams(params);\n const queryString = searchParams.toString();\n return queryString ? `?${queryString}` : \"\";\n }\n\n /**\n * Lists all apps in the project\n *\n * @returns Array of app items\n *\n * @example\n * ```typescript\n * const apps = await client.listApps();\n * console.log('Available apps:', apps);\n * ```\n */\n async listApps(): Promise<AppItem[]> {\n const query = this.buildQueryParams();\n return this.request<AppItem[]>(`/${this.config.projectId}/app${query}`);\n }\n\n /**\n * Gets data for a specific app\n *\n * @param appPath - Relative path to the app file (e.g., 'my-app.app.yml')\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.getAppData('dashboard.app.yml');\n * if (data.error) {\n * console.error('Error:', data.error);\n * } else {\n * console.log('App data:', data.data);\n * }\n * ```\n */\n async getAppData(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}${query}`,\n );\n }\n\n /**\n * Runs an app and returns fresh data (bypasses cache)\n *\n * @param appPath - Relative path to the app file\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.runApp('dashboard.app.yml');\n * console.log('Fresh app data:', data.data);\n * ```\n */\n async runApp(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}/run${query}`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Gets display configurations for an app\n *\n * @param appPath - Relative path to the app file\n * @returns Display configurations with potential errors\n *\n * @example\n * ```typescript\n * const displays = await client.getDisplays('dashboard.app.yml');\n * displays.displays.forEach(d => {\n * if (d.error) {\n * console.error('Display error:', d.error);\n * } else {\n * console.log('Display:', d.display);\n * }\n * });\n * ```\n */\n async getDisplays(appPath: string): Promise<GetDisplaysResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<GetDisplaysResponse>(\n `/${this.config.projectId}/app/${pathb64}/displays${query}`,\n );\n }\n\n /**\n * Gets a file from the app state directory (e.g., generated charts, images)\n *\n * This is useful for retrieving generated assets like charts, images, or other\n * files produced by app workflows and stored in the state directory.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Blob containing the file data\n *\n * @example\n * ```typescript\n * // Get a generated chart image\n * const blob = await client.getFile('charts/sales-chart.png');\n * const imageUrl = URL.createObjectURL(blob);\n *\n * // Use in an img tag\n * document.querySelector('img').src = imageUrl;\n * ```\n *\n * @example\n * ```typescript\n * // Download a file\n * const blob = await client.getFile('exports/data.csv');\n * const a = document.createElement('a');\n * a.href = URL.createObjectURL(blob);\n * a.download = 'data.csv';\n * a.click();\n * ```\n */\n async getFile(filePath: string): Promise<Blob> {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return this.request<Blob>(\n `/${this.config.projectId}/app/file/${pathb64}${query}`,\n {\n headers: {\n Accept: \"application/octet-stream\",\n },\n },\n );\n }\n\n /**\n * Gets a file URL for direct browser access\n *\n * This returns a URL that can be used directly in img tags, fetch calls, etc.\n * The URL includes authentication via query parameters.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Full URL to the file\n *\n * @example\n * ```typescript\n * const imageUrl = client.getFileUrl('charts/sales-chart.png');\n *\n * // Use directly in img tag (in environments where query-based auth is supported)\n * document.querySelector('img').src = imageUrl;\n * ```\n */\n getFileUrl(filePath: string): string {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return `${this.config.baseUrl}/${this.config.projectId}/app/file/${pathb64}${query}`;\n }\n\n /**\n * Fetches a parquet file and parses it into table data\n *\n * @param filePath - Relative path to the parquet file\n * @param limit - Maximum number of rows to return (default: 100)\n * @returns TableData with columns and rows\n *\n * @example\n * ```typescript\n * const tableData = await client.getTableData('data/sales.parquet', 50);\n * console.log(tableData.columns);\n * console.log(tableData.rows);\n * console.log(`Total rows: ${tableData.total_rows}`);\n * ```\n */\n async getTableData(\n filePath: string,\n limit: number = 100,\n ): Promise<TableData> {\n const blob = await this.getFile(filePath);\n const result = await readParquet(blob, \"data\", limit);\n\n return {\n columns: result.columns,\n rows: result.rows,\n total_rows: result.rowCount,\n };\n }\n}\n","import { OxyClient } from \"./client\";\nimport { OxyConfig, createConfigAsync } from \"./config\";\nimport { ParquetReader, QueryResult } from \"./parquet\";\nimport { DataContainer } from \"./types\";\n\n/**\n * OxySDK provides a unified interface for fetching data from Oxy and querying it with SQL.\n * It combines OxyClient (for API calls) and ParquetReader (for SQL queries) into a single,\n * easy-to-use interface.\n *\n * @example\n * ```typescript\n * // Create SDK instance\n * const sdk = new OxySDK({ apiKey: 'your-key', projectId: 'your-project' });\n *\n * // Load a parquet file and query it\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales WHERE amount > 1000');\n * console.log(result.rows);\n *\n * // Clean up when done\n * await sdk.close();\n * ```\n */\nexport class OxySDK {\n private client: OxyClient;\n private reader: ParquetReader;\n\n constructor(config: OxyConfig) {\n this.client = new OxyClient(config);\n this.reader = new ParquetReader();\n }\n\n /**\n * Creates an OxySDK instance asynchronously with support for postMessage authentication\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxySDK instance\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const sdk = await OxySDK.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id'\n * });\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxySDK> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxySDK(resolvedConfig);\n }\n\n /**\n * Load a Parquet file from Oxy and register it for SQL queries\n *\n * @param filePath - Path to the parquet file in the app state directory\n * @param tableName - Name to use for the table in SQL queries\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * await sdk.loadFile('data/customers.parquet', 'customers');\n *\n * const result = await sdk.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async loadFile(filePath: string, tableName: string): Promise<void> {\n const blob = await this.client.getFile(filePath);\n await this.reader.registerParquet(blob, tableName);\n }\n\n /**\n * Load multiple Parquet files at once\n *\n * @param files - Array of file paths and table names\n *\n * @example\n * ```typescript\n * await sdk.loadFiles([\n * { filePath: 'data/sales.parquet', tableName: 'sales' },\n * { filePath: 'data/customers.parquet', tableName: 'customers' },\n * { filePath: 'data/products.parquet', tableName: 'products' }\n * ]);\n *\n * const result = await sdk.query('SELECT * FROM sales');\n * ```\n */\n async loadFiles(\n files: Array<{ filePath: string; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.loadFile(file.filePath, file.tableName);\n }\n }\n\n /**\n * Load all data from an app's data container\n *\n * This fetches the app's data and registers all parquet files using their container keys as table names.\n *\n * @param appPath - Path to the app file\n * @returns DataContainer with file references\n *\n * @example\n * ```typescript\n * // If app has data: { sales: { file_path: 'data/sales.parquet' } }\n * const data = await sdk.loadAppData('dashboard.app.yml');\n * // Now you can query the 'sales' table\n * const result = await sdk.query('SELECT * FROM sales LIMIT 10');\n * ```\n */\n async loadAppData(appPath: string): Promise<DataContainer | null> {\n const appDataResponse = await this.client.getAppData(appPath);\n\n if (appDataResponse.error) {\n throw new Error(`Failed to load app data: ${appDataResponse.error}`);\n }\n\n if (!appDataResponse.data) {\n return null;\n }\n\n // Load each file in the data container\n const loadPromises = Object.entries(appDataResponse.data).map(\n async ([tableName, fileRef]) => {\n await this.loadFile(fileRef.file_path, tableName);\n },\n );\n\n await Promise.all(loadPromises);\n\n return appDataResponse.data;\n }\n\n /**\n * Execute a SQL query against loaded data\n *\n * @param sql - SQL query to execute\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n *\n * const result = await sdk.query('SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result.columns); // ['product', 'total']\n * console.log(result.rows); // [['Product A', 1000], ['Product B', 2000]]\n * console.log(result.rowCount); // 2\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n return this.reader.query(sql);\n }\n\n /**\n * Get all data from a loaded table\n *\n * @param tableName - Name of the table\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const allData = await sdk.getAll('sales');\n * const first100 = await sdk.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n return this.reader.getAll(tableName, limit);\n }\n\n /**\n * Get schema information for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Schema information\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const schema = await sdk.getSchema('sales');\n * console.log(schema.columns); // ['column_name', 'column_type', ...]\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.reader.getSchema(tableName);\n }\n\n /**\n * Get row count for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Number of rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const count = await sdk.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n return this.reader.count(tableName);\n }\n\n /**\n * Get direct access to the underlying OxyClient\n *\n * Useful for advanced operations like listing apps, getting displays, etc.\n *\n * @returns The OxyClient instance\n *\n * @example\n * ```typescript\n * const apps = await sdk.getClient().listApps();\n * const displays = await sdk.getClient().getDisplays('my-app.app.yml');\n * ```\n */\n getClient(): OxyClient {\n return this.client;\n }\n\n /**\n * Get direct access to the underlying ParquetReader\n *\n * Useful for advanced operations like registering blobs directly.\n *\n * @returns The ParquetReader instance\n *\n * @example\n * ```typescript\n * const myBlob = new Blob([parquetData]);\n * await sdk.getReader().registerParquet(myBlob, 'mydata');\n * ```\n */\n getReader(): ParquetReader {\n return this.reader;\n }\n\n /**\n * Close and cleanup all resources\n *\n * This clears all loaded data and releases resources. Call this when you're done with the SDK.\n *\n * @example\n * ```typescript\n * const sdk = new OxySDK({ apiKey: 'key', projectId: 'project' });\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales');\n * await sdk.close(); // Clean up\n * ```\n */\n async close(): Promise<void> {\n await this.reader.close();\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n ReactNode,\n} from \"react\";\nimport { OxySDK } from \"./sdk\";\nimport { OxyConfig } from \"./config\";\n\n/**\n * Context value provided to child components\n */\nexport interface OxyContextValue {\n sdk: OxySDK | null;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * React context for OxySDK\n */\nconst OxyContext = createContext<OxyContextValue | undefined>(undefined);\n\n/**\n * Props for OxyProvider component\n */\nexport interface OxyProviderProps {\n children: ReactNode;\n config?: Partial<OxyConfig>;\n /**\n * If true, uses async initialization (supports postMessage auth in iframes)\n * If false, uses synchronous initialization with provided config\n */\n useAsync?: boolean;\n /**\n * Called when SDK is successfully initialized\n */\n onReady?: (sdk: OxySDK) => void;\n /**\n * Called when initialization fails\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Provider component that initializes and provides OxySDK to child components\n *\n * @example\n * ```tsx\n * // Synchronous initialization with config\n * function App() {\n * return (\n * <OxyProvider config={{\n * apiKey: 'your-key',\n * projectId: 'your-project',\n * baseUrl: 'https://api.oxy.tech'\n * }}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Async initialization (for iframe/postMessage auth)\n * function App() {\n * return (\n * <OxyProvider\n * useAsync\n * config={{ parentOrigin: 'https://app.example.com' }}\n * >\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With environment variables\n * import { createConfig } from '@oxy/sdk';\n *\n * function App() {\n * return (\n * <OxyProvider config={createConfig()}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n */\nexport function OxyProvider({\n children,\n config,\n useAsync = false,\n onReady,\n onError,\n}: OxyProviderProps) {\n const [sdk, setSdk] = useState<OxySDK | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n let sdkInstance: OxySDK | null = null;\n\n async function initializeSDK() {\n try {\n setIsLoading(true);\n setError(null);\n\n if (useAsync) {\n // Async initialization (supports postMessage auth)\n sdkInstance = await OxySDK.create(config);\n } else {\n // Sync initialization with provided config\n if (!config) {\n throw new Error(\n \"Config is required when useAsync is false. Either provide config or set useAsync=true.\",\n );\n }\n sdkInstance = new OxySDK(config as OxyConfig);\n }\n\n if (mounted) {\n setSdk(sdkInstance);\n setIsLoading(false);\n onReady?.(sdkInstance);\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Failed to initialize SDK\");\n\n if (mounted) {\n setError(error);\n setIsLoading(false);\n onError?.(error);\n }\n }\n }\n\n initializeSDK();\n\n // Cleanup function\n return () => {\n mounted = false;\n if (sdkInstance) {\n sdkInstance.close().catch(console.error);\n }\n };\n }, [config, useAsync, onReady, onError]);\n\n return (\n <OxyContext.Provider value={{ sdk, isLoading, error }}>\n {children}\n </OxyContext.Provider>\n );\n}\n\n/**\n * Hook to access OxySDK from child components\n *\n * @throws {Error} If used outside of OxyProvider\n * @returns {OxyContextValue} The SDK instance, loading state, and error\n *\n * @example\n * ```tsx\n * function Dashboard() {\n * const { sdk, isLoading, error } = useOxy();\n *\n * useEffect(() => {\n * if (sdk) {\n * sdk.loadAppData('dashboard.app.yml')\n * .then(() => sdk.query('SELECT * FROM my_table'))\n * .then(result => console.log(result));\n * }\n * }, [sdk]);\n *\n * if (isLoading) return <div>Loading SDK...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!sdk) return null;\n *\n * return <div>Dashboard</div>;\n * }\n * ```\n */\nexport function useOxy(): OxyContextValue {\n const context = useContext(OxyContext);\n\n if (context === undefined) {\n throw new Error(\"useOxy must be used within an OxyProvider\");\n }\n\n return context;\n}\n\n/**\n * Hook to access OxySDK that throws if not ready\n *\n * This is a convenience hook that returns the SDK directly or throws an error if not initialized.\n * Use this when you know the SDK should be ready.\n *\n * @throws {Error} If used outside of OxyProvider or if SDK is not initialized\n * @returns {OxySDK} The SDK instance\n *\n * @example\n * ```tsx\n * function DataTable() {\n * const sdk = useOxySDK();\n * const [data, setData] = useState(null);\n *\n * useEffect(() => {\n * sdk.loadFile('data.parquet', 'data')\n * .then(() => sdk.query('SELECT * FROM data LIMIT 100'))\n * .then(setData);\n * }, [sdk]);\n *\n * return <table>...</table>;\n * }\n * ```\n */\nexport function useOxySDK(): OxySDK {\n const { sdk, isLoading, error } = useOxy();\n\n if (error) {\n throw error;\n }\n\n if (isLoading || !sdk) {\n throw new Error(\"OxySDK is not yet initialized\");\n }\n\n return sdk;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["isInIframe","requestAuthFromParent","error"],"sources":["../src/config.ts","../src/parquet.ts","../src/client.ts","../src/sdk.ts","../src/react.tsx"],"sourcesContent":["/**\n * Configuration for the Oxy SDK\n */\nexport interface OxyConfig {\n /**\n * Base URL of the Oxy API (e.g., 'https://api.oxy.tech' or 'http://localhost:3000')\n */\n baseUrl: string;\n\n /**\n * API key for authentication (optional for local development)\n */\n apiKey?: string;\n\n /**\n * Project ID (UUID)\n */\n projectId: string;\n\n /**\n * Optional branch name (defaults to current branch if not specified)\n */\n branch?: string;\n\n /**\n * Request timeout in milliseconds (default: 30000)\n */\n timeout?: number;\n\n /**\n * Parent window origin for postMessage authentication (iframe scenarios)\n * Required when using postMessage auth for security.\n * Example: 'https://app.example.com'\n * Use '*' only in development!\n */\n parentOrigin?: string;\n\n /**\n * Disable automatic postMessage authentication even if in iframe\n * Set to true if you want to provide API key manually in iframe context\n */\n disableAutoAuth?: boolean;\n}\n\n/**\n * Safely get environment variable in both Node.js and browser environments\n */\nfunction getEnvVar(name: string): string | undefined {\n // Check if we're in Node.js\n if (typeof process !== 'undefined' && process.env) {\n return process.env[name];\n }\n\n // Check if we're in a Vite environment (browser)\n if (typeof import.meta !== 'undefined' && (import.meta as any).env) {\n // Try with VITE_ prefix first (Vite convention)\n const viteValue = (import.meta as any).env[`VITE_${name}`];\n if (viteValue !== undefined) return viteValue;\n\n // Try without prefix\n return (import.meta as any).env[name];\n }\n\n return undefined;\n}\n\n/**\n * Creates an Oxy configuration from environment variables\n *\n * Environment variables:\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns OxyConfig object\n * @throws Error if required environment variables are missing\n */\nexport function createConfig(overrides?: Partial<OxyConfig>): OxyConfig {\n const baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n const apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n const projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n\n/**\n * Creates an Oxy configuration asynchronously with support for postMessage authentication\n *\n * This is the recommended method for iframe scenarios where authentication\n * needs to be obtained from the parent window via postMessage.\n *\n * When running in an iframe without an API key, this function will:\n * 1. Detect the iframe context\n * 2. Send an authentication request to the parent window\n * 3. Wait for the parent to respond with credentials\n * 4. Return the configured client\n *\n * Environment variables (fallback):\n * - OXY_URL: Base URL of the Oxy API\n * - OXY_API_KEY: API key for authentication\n * - OXY_PROJECT_ID: Project ID (UUID)\n * - OXY_BRANCH: (Optional) Branch name\n *\n * @param overrides - Optional configuration overrides\n * @returns Promise resolving to OxyConfig object\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // Automatic iframe detection and authentication\n * const config = await createConfigAsync({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n * ```\n */\nexport async function createConfigAsync(\n overrides?: Partial<OxyConfig>,\n): Promise<OxyConfig> {\n // Import postMessage utilities (dynamic to avoid circular deps)\n const { isInIframe } = await import(\"./auth/postMessage\");\n\n // Start with environment variables and overrides\n let baseUrl = overrides?.baseUrl || getEnvVar('OXY_URL');\n let apiKey = overrides?.apiKey || getEnvVar('OXY_API_KEY');\n let projectId = overrides?.projectId || getEnvVar('OXY_PROJECT_ID');\n\n const disableAutoAuth = overrides?.disableAutoAuth ?? false;\n const parentOrigin = overrides?.parentOrigin;\n\n // Automatic iframe detection and authentication\n if (!disableAutoAuth && isInIframe() && !apiKey) {\n if (!parentOrigin) {\n logWarningAboutMissingParentOrigin();\n } else {\n apiKey = await attemptPostMessageAuth(\n parentOrigin,\n overrides?.timeout || 5000,\n apiKey,\n projectId,\n baseUrl,\n )\n .then((result) => {\n if (result.projectId) projectId = result.projectId;\n if (result.baseUrl) baseUrl = result.baseUrl;\n return result.apiKey;\n })\n .catch((error) => {\n console.error(\n \"[Oxy SDK] Failed to authenticate via postMessage:\",\n (error as Error).message,\n );\n return apiKey;\n });\n }\n }\n\n return createFinalConfig(baseUrl, apiKey, projectId, overrides);\n}\n\nfunction logWarningAboutMissingParentOrigin(): void {\n console.warn(\n \"[Oxy SDK] Running in iframe without API key and no parentOrigin specified. \" +\n \"PostMessage authentication will be skipped. \" +\n \"Provide parentOrigin config to enable automatic authentication.\",\n );\n}\n\nasync function attemptPostMessageAuth(\n parentOrigin: string,\n timeout: number,\n currentApiKey: string | undefined,\n currentProjectId: string | undefined,\n currentBaseUrl: string | undefined,\n): Promise<{ apiKey?: string; projectId?: string; baseUrl?: string }> {\n const { requestAuthFromParent } = await import(\"./auth/postMessage\");\n const authResult = await requestAuthFromParent({ parentOrigin, timeout });\n\n console.log(\"[Oxy SDK] Successfully authenticated via postMessage\");\n\n return {\n apiKey: authResult.apiKey || currentApiKey,\n projectId: authResult.projectId || currentProjectId,\n baseUrl: authResult.baseUrl || currentBaseUrl,\n };\n}\n\nfunction createFinalConfig(\n baseUrl: string | undefined,\n apiKey: string | undefined,\n projectId: string | undefined,\n overrides?: Partial<OxyConfig>,\n): OxyConfig {\n // Validation\n if (!baseUrl) {\n throw new Error(\n \"OXY_URL environment variable or baseUrl config is required\",\n );\n }\n\n if (!projectId) {\n throw new Error(\n \"OXY_PROJECT_ID environment variable or projectId config is required\",\n );\n }\n\n return {\n baseUrl: baseUrl.replace(/\\/$/, \"\"), // Remove trailing slash\n apiKey,\n projectId,\n branch: overrides?.branch || getEnvVar('OXY_BRANCH'),\n timeout: overrides?.timeout || 30000,\n parentOrigin: overrides?.parentOrigin,\n disableAutoAuth: overrides?.disableAutoAuth,\n };\n}\n","import * as duckdb from \"@duckdb/duckdb-wasm\";\n\nlet dbInstance: duckdb.AsyncDuckDB | null = null;\nlet connection: duckdb.AsyncDuckDBConnection | null = null;\n\n// Queue to serialize operations and prevent race conditions\nlet operationQueue = Promise.resolve();\n\n/**\n * Enqueue an operation to prevent race conditions on shared DuckDB instance\n */\nfunction enqueueOperation<T>(operation: () => Promise<T>): Promise<T> {\n const currentOperation = operationQueue.then(operation, operation);\n operationQueue = currentOperation.then(\n () => {\n return;\n },\n () => {\n return;\n },\n );\n return currentOperation;\n}\n\n/**\n * Initialize DuckDB-WASM instance\n */\nexport async function initializeDuckDB(): Promise<duckdb.AsyncDuckDB> {\n if (dbInstance) {\n return dbInstance;\n }\n\n const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();\n\n // Select a bundle based on browser features\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);\n\n const worker_url = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], {\n type: \"text/javascript\",\n }),\n );\n\n const worker = new Worker(worker_url);\n const logger = new duckdb.ConsoleLogger();\n\n dbInstance = new duckdb.AsyncDuckDB(logger, worker);\n await dbInstance.instantiate(bundle.mainModule, bundle.pthreadWorker);\n URL.revokeObjectURL(worker_url);\n\n return dbInstance;\n}\n\n/**\n * Get or create a DuckDB connection\n */\nasync function getConnection(): Promise<duckdb.AsyncDuckDBConnection> {\n if (connection) {\n return connection;\n }\n\n const db = await initializeDuckDB();\n connection = await db.connect();\n return connection;\n}\n\n/**\n * Query result interface\n */\nexport interface QueryResult {\n columns: string[];\n rows: unknown[][];\n rowCount: number;\n}\n\n/**\n * ParquetReader provides methods to read and query Parquet files.\n * Supports registering multiple Parquet files with different table names.\n */\nexport class ParquetReader {\n private tableMap: Map<string, string> = new Map(); // Maps user table name -> internal unique table name\n\n constructor() {\n // No default table name - all tables must be explicitly named\n }\n\n /**\n * Generate a unique internal table name to prevent conflicts\n */\n private generateInternalTableName(tableName: string): string {\n // Note: Math.random() is acceptable here as uniqueness is only needed for table naming (not security-critical)\n /* eslint-disable sonarjs/pseudo-random */\n const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n /* eslint-enable sonarjs/pseudo-random */\n return `${tableName}_${uniqueId}`;\n }\n\n /**\n * Register a Parquet file from a Blob with a specific table name\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (required)\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const reader = new ParquetReader();\n * await reader.registerParquet(blob, 'sales');\n * ```\n *\n * @example\n * ```typescript\n * // Register multiple files\n * const reader = new ParquetReader();\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerParquet(blob: Blob, tableName: string): Promise<void> {\n const internalTableName = this.generateInternalTableName(tableName);\n\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Convert blob to Uint8Array\n const arrayBuffer = await blob.arrayBuffer();\n const uint8Array = new Uint8Array(arrayBuffer);\n\n // Register the file with DuckDB using unique name\n await db.registerFileBuffer(\n `${internalTableName}.parquet`,\n uint8Array,\n );\n\n // Drop table if it exists\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error if table doesn't exist\n }\n\n // Create table from parquet\n await conn.query(\n `CREATE TABLE ${internalTableName} AS SELECT * FROM '${internalTableName}.parquet'`,\n );\n\n // Store mapping\n this.tableMap.set(tableName, internalTableName);\n });\n }\n\n /**\n * Register multiple Parquet files at once\n *\n * @param files - Array of objects containing blob and tableName\n *\n * @example\n * ```typescript\n * const reader = new ParquetReader();\n * await reader.registerMultipleParquet([\n * { blob: salesBlob, tableName: 'sales' },\n * { blob: customersBlob, tableName: 'customers' },\n * { blob: productsBlob, tableName: 'products' }\n * ]);\n * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');\n * ```\n */\n async registerMultipleParquet(\n files: Array<{ blob: Blob; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.registerParquet(file.blob, file.tableName);\n }\n }\n\n /**\n * Execute a SQL query against the registered Parquet data\n *\n * @param sql - SQL query string\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * const result = await reader.query('SELECT * FROM sales LIMIT 10');\n * console.log(result.columns);\n * console.log(result.rows);\n * ```\n *\n * @example\n * ```typescript\n * // Query multiple tables\n * await reader.registerParquet(salesBlob, 'sales');\n * await reader.registerParquet(customersBlob, 'customers');\n * const result = await reader.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n if (this.tableMap.size === 0) {\n throw new Error(\n \"No Parquet files registered. Call registerParquet() first.\",\n );\n }\n\n return enqueueOperation(async () => {\n const conn = await getConnection();\n\n // Replace all registered table names with their internal unique names\n let rewrittenSql = sql;\n for (const [userTableName, internalTableName] of this.tableMap.entries()) {\n rewrittenSql = rewrittenSql.replace(\n new RegExp(`\\\\b${userTableName}\\\\b`, \"g\"),\n internalTableName,\n );\n }\n\n const result = await conn.query(rewrittenSql);\n\n const columns = result.schema.fields.map((field) => field.name);\n const rows: unknown[][] = [];\n\n // Convert Arrow table to rows\n for (let i = 0; i < result.numRows; i++) {\n const row: unknown[] = [];\n for (let j = 0; j < result.numCols; j++) {\n const col = result.getChildAt(j);\n row.push(col?.get(i));\n }\n rows.push(row);\n }\n\n return {\n columns,\n rows,\n rowCount: result.numRows,\n };\n });\n }\n\n /**\n * Get all data from a registered table\n *\n * @param tableName - Name of the table to query\n * @param limit - Maximum number of rows to return (default: all)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const allData = await reader.getAll('sales');\n * const first100 = await reader.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n const limitClause = limit ? ` LIMIT ${limit}` : \"\";\n return this.query(`SELECT * FROM ${tableName}${limitClause}`);\n }\n\n /**\n * Get table schema information\n *\n * @param tableName - Name of the table to describe\n * @returns Schema information\n *\n * @example\n * ```typescript\n * const schema = await reader.getSchema('sales');\n * console.log(schema.columns); // ['id', 'name', 'sales']\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.query(`DESCRIBE ${tableName}`);\n }\n\n /**\n * Get row count for a table\n *\n * @param tableName - Name of the table to count\n * @returns Number of rows in the table\n *\n * @example\n * ```typescript\n * const count = await reader.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n const result = await this.query(\n `SELECT COUNT(*) as count FROM ${tableName}`,\n );\n return result.rows[0][0] as number;\n }\n\n /**\n * Close and cleanup all registered resources\n */\n async close(): Promise<void> {\n if (this.tableMap.size > 0) {\n await enqueueOperation(async () => {\n const conn = await getConnection();\n const db = await initializeDuckDB();\n\n // Drop all registered tables and file buffers\n for (const [, internalTableName] of this.tableMap.entries()) {\n // Drop the table using internal unique name\n try {\n await conn.query(`DROP TABLE IF EXISTS ${internalTableName}`);\n } catch {\n // Ignore error\n }\n\n // Drop the registered file buffer using internal unique name\n try {\n await db.dropFile(`${internalTableName}.parquet`);\n } catch {\n // Ignore error if file doesn't exist\n }\n }\n\n // Clear the table map\n this.tableMap.clear();\n });\n }\n }\n}\n\n/**\n * Helper function to quickly read a Parquet blob and execute a query\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table in queries (default: 'data')\n * @param sql - SQL query to execute (optional, defaults to SELECT * FROM tableName)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const result = await queryParquet(blob, 'sales', 'SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result);\n * ```\n */\nexport async function queryParquet(\n blob: Blob,\n tableName: string = \"data\",\n sql?: string,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const query = sql || `SELECT * FROM ${tableName}`;\n const result = await reader.query(query);\n\n await reader.close();\n return result;\n}\n\n/**\n * Helper function to read Parquet file and get all data\n *\n * @param blob - Parquet file as Blob\n * @param tableName - Name to use for the table (default: 'data')\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * const blob = await client.getFile('data/sales.parquet');\n * const data = await readParquet(blob, 'sales', 1000);\n * console.log(`Loaded ${data.rowCount} rows`);\n * ```\n */\nexport async function readParquet(\n blob: Blob,\n tableName: string = \"data\",\n limit?: number,\n): Promise<QueryResult> {\n const reader = new ParquetReader();\n\n await reader.registerParquet(blob, tableName);\n\n const result = await reader.getAll(tableName, limit);\n\n await reader.close();\n return result;\n}\n","import { OxyConfig, createConfigAsync } from \"./config\";\nimport {\n AppItem,\n AppDataResponse,\n GetDisplaysResponse,\n ApiError,\n TableData,\n} from \"./types\";\nimport { readParquet } from \"./parquet\";\n\n/**\n * Oxy API Client for interacting with Oxy data\n */\nexport class OxyClient {\n private config: OxyConfig;\n\n constructor(config: OxyConfig) {\n this.config = config;\n }\n\n /**\n * Creates an OxyClient instance asynchronously with support for postMessage authentication\n *\n * This is the recommended method when using the SDK in an iframe that needs to\n * obtain authentication from the parent window via postMessage.\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxyClient instance\n * @throws Error if required configuration is missing\n * @throws PostMessageAuthTimeoutError if parent doesn't respond\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const client = await OxyClient.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id',\n * baseUrl: 'https://api.oxy.tech'\n * });\n *\n * // Use the client normally\n * const apps = await client.listApps();\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxyClient> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxyClient(resolvedConfig);\n }\n\n /**\n * Encodes a file path to base64 for use in API URLs\n */\n private encodePathBase64(path: string): string {\n if (typeof Buffer !== \"undefined\") {\n // Node.js environment\n return Buffer.from(path).toString(\"base64\");\n } else {\n // Browser environment\n return btoa(path);\n }\n }\n\n /**\n * Makes an authenticated HTTP request to the Oxy API\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...((options.headers as Record<string, string>) || {}),\n };\n\n // Only add Authorization header if API key is provided (optional for local dev)\n if (this.config.apiKey) {\n headers[\"Authorization\"] = `Bearer ${this.config.apiKey}`;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n this.config.timeout || 30000,\n );\n\n try {\n const response = await fetch(url, {\n ...options,\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n const error: ApiError = {\n message: `API request failed: ${response.statusText}`,\n status: response.status,\n details: errorText,\n };\n throw error;\n }\n\n // Handle binary responses\n const acceptHeader =\n typeof options.headers === \"object\" && options.headers !== null\n ? (options.headers as Record<string, string>)[\"Accept\"]\n : undefined;\n if (acceptHeader === \"application/octet-stream\") {\n return response.blob() as Promise<T>;\n }\n\n return response.json();\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\n `Request timeout after ${this.config.timeout || 30000}ms`,\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Builds query parameters including optional branch\n */\n private buildQueryParams(\n additionalParams: Record<string, string> = {},\n ): string {\n const params: Record<string, string> = { ...additionalParams };\n\n if (this.config.branch) {\n params.branch = this.config.branch;\n }\n\n const searchParams = new URLSearchParams(params);\n const queryString = searchParams.toString();\n return queryString ? `?${queryString}` : \"\";\n }\n\n /**\n * Lists all apps in the project\n *\n * @returns Array of app items\n *\n * @example\n * ```typescript\n * const apps = await client.listApps();\n * console.log('Available apps:', apps);\n * ```\n */\n async listApps(): Promise<AppItem[]> {\n const query = this.buildQueryParams();\n return this.request<AppItem[]>(`/${this.config.projectId}/app${query}`);\n }\n\n /**\n * Gets data for a specific app\n *\n * @param appPath - Relative path to the app file (e.g., 'my-app.app.yml')\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.getAppData('dashboard.app.yml');\n * if (data.error) {\n * console.error('Error:', data.error);\n * } else {\n * console.log('App data:', data.data);\n * }\n * ```\n */\n async getAppData(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}${query}`,\n );\n }\n\n /**\n * Runs an app and returns fresh data (bypasses cache)\n *\n * @param appPath - Relative path to the app file\n * @returns App data response\n *\n * @example\n * ```typescript\n * const data = await client.runApp('dashboard.app.yml');\n * console.log('Fresh app data:', data.data);\n * ```\n */\n async runApp(appPath: string): Promise<AppDataResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<AppDataResponse>(\n `/${this.config.projectId}/app/${pathb64}/run${query}`,\n { method: \"POST\" },\n );\n }\n\n /**\n * Gets display configurations for an app\n *\n * @param appPath - Relative path to the app file\n * @returns Display configurations with potential errors\n *\n * @example\n * ```typescript\n * const displays = await client.getDisplays('dashboard.app.yml');\n * displays.displays.forEach(d => {\n * if (d.error) {\n * console.error('Display error:', d.error);\n * } else {\n * console.log('Display:', d.display);\n * }\n * });\n * ```\n */\n async getDisplays(appPath: string): Promise<GetDisplaysResponse> {\n const pathb64 = this.encodePathBase64(appPath);\n const query = this.buildQueryParams();\n return this.request<GetDisplaysResponse>(\n `/${this.config.projectId}/app/${pathb64}/displays${query}`,\n );\n }\n\n /**\n * Gets a file from the app state directory (e.g., generated charts, images)\n *\n * This is useful for retrieving generated assets like charts, images, or other\n * files produced by app workflows and stored in the state directory.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Blob containing the file data\n *\n * @example\n * ```typescript\n * // Get a generated chart image\n * const blob = await client.getFile('charts/sales-chart.png');\n * const imageUrl = URL.createObjectURL(blob);\n *\n * // Use in an img tag\n * document.querySelector('img').src = imageUrl;\n * ```\n *\n * @example\n * ```typescript\n * // Download a file\n * const blob = await client.getFile('exports/data.csv');\n * const a = document.createElement('a');\n * a.href = URL.createObjectURL(blob);\n * a.download = 'data.csv';\n * a.click();\n * ```\n */\n async getFile(filePath: string): Promise<Blob> {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return this.request<Blob>(\n `/${this.config.projectId}/app/file/${pathb64}${query}`,\n {\n headers: {\n Accept: \"application/octet-stream\",\n },\n },\n );\n }\n\n /**\n * Gets a file URL for direct browser access\n *\n * This returns a URL that can be used directly in img tags, fetch calls, etc.\n * The URL includes authentication via query parameters.\n *\n * @param filePath - Relative path to the file in state directory\n * @returns Full URL to the file\n *\n * @example\n * ```typescript\n * const imageUrl = client.getFileUrl('charts/sales-chart.png');\n *\n * // Use directly in img tag (in environments where query-based auth is supported)\n * document.querySelector('img').src = imageUrl;\n * ```\n */\n getFileUrl(filePath: string): string {\n const pathb64 = this.encodePathBase64(filePath);\n const query = this.buildQueryParams();\n return `${this.config.baseUrl}/${this.config.projectId}/app/file/${pathb64}${query}`;\n }\n\n /**\n * Fetches a parquet file and parses it into table data\n *\n * @param filePath - Relative path to the parquet file\n * @param limit - Maximum number of rows to return (default: 100)\n * @returns TableData with columns and rows\n *\n * @example\n * ```typescript\n * const tableData = await client.getTableData('data/sales.parquet', 50);\n * console.log(tableData.columns);\n * console.log(tableData.rows);\n * console.log(`Total rows: ${tableData.total_rows}`);\n * ```\n */\n async getTableData(\n filePath: string,\n limit: number = 100,\n ): Promise<TableData> {\n const blob = await this.getFile(filePath);\n const result = await readParquet(blob, \"data\", limit);\n\n return {\n columns: result.columns,\n rows: result.rows,\n total_rows: result.rowCount,\n };\n }\n}\n","import { OxyClient } from \"./client\";\nimport { OxyConfig, createConfigAsync } from \"./config\";\nimport { ParquetReader, QueryResult } from \"./parquet\";\nimport { DataContainer } from \"./types\";\n\n/**\n * OxySDK provides a unified interface for fetching data from Oxy and querying it with SQL.\n * It combines OxyClient (for API calls) and ParquetReader (for SQL queries) into a single,\n * easy-to-use interface.\n *\n * @example\n * ```typescript\n * // Create SDK instance\n * const sdk = new OxySDK({ apiKey: 'your-key', projectId: 'your-project' });\n *\n * // Load a parquet file and query it\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales WHERE amount > 1000');\n * console.log(result.rows);\n *\n * // Clean up when done\n * await sdk.close();\n * ```\n */\nexport class OxySDK {\n private client: OxyClient;\n private reader: ParquetReader;\n\n constructor(config: OxyConfig) {\n this.client = new OxyClient(config);\n this.reader = new ParquetReader();\n }\n\n /**\n * Creates an OxySDK instance asynchronously with support for postMessage authentication\n *\n * @param config - Optional configuration overrides\n * @returns Promise resolving to OxySDK instance\n *\n * @example\n * ```typescript\n * // In an iframe - automatic postMessage auth\n * const sdk = await OxySDK.create({\n * parentOrigin: 'https://app.example.com',\n * projectId: 'my-project-id'\n * });\n * ```\n */\n static async create(config?: Partial<OxyConfig>): Promise<OxySDK> {\n const resolvedConfig = await createConfigAsync(config);\n return new OxySDK(resolvedConfig);\n }\n\n /**\n * Load a Parquet file from Oxy and register it for SQL queries\n *\n * @param filePath - Path to the parquet file in the app state directory\n * @param tableName - Name to use for the table in SQL queries\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * await sdk.loadFile('data/customers.parquet', 'customers');\n *\n * const result = await sdk.query(`\n * SELECT s.*, c.name\n * FROM sales s\n * JOIN customers c ON s.customer_id = c.id\n * `);\n * ```\n */\n async loadFile(filePath: string, tableName: string): Promise<void> {\n const blob = await this.client.getFile(filePath);\n await this.reader.registerParquet(blob, tableName);\n }\n\n /**\n * Load multiple Parquet files at once\n *\n * @param files - Array of file paths and table names\n *\n * @example\n * ```typescript\n * await sdk.loadFiles([\n * { filePath: 'data/sales.parquet', tableName: 'sales' },\n * { filePath: 'data/customers.parquet', tableName: 'customers' },\n * { filePath: 'data/products.parquet', tableName: 'products' }\n * ]);\n *\n * const result = await sdk.query('SELECT * FROM sales');\n * ```\n */\n async loadFiles(\n files: Array<{ filePath: string; tableName: string }>,\n ): Promise<void> {\n for (const file of files) {\n await this.loadFile(file.filePath, file.tableName);\n }\n }\n\n /**\n * Load all data from an app's data container\n *\n * This fetches the app's data and registers all parquet files using their container keys as table names.\n *\n * @param appPath - Path to the app file\n * @returns DataContainer with file references\n *\n * @example\n * ```typescript\n * // If app has data: { sales: { file_path: 'data/sales.parquet' } }\n * const data = await sdk.loadAppData('dashboard.app.yml');\n * // Now you can query the 'sales' table\n * const result = await sdk.query('SELECT * FROM sales LIMIT 10');\n * ```\n */\n async loadAppData(appPath: string): Promise<DataContainer | null> {\n const appDataResponse = await this.client.getAppData(appPath);\n\n if (appDataResponse.error) {\n throw new Error(`Failed to load app data: ${appDataResponse.error}`);\n }\n\n if (!appDataResponse.data) {\n return null;\n }\n\n // Load each file in the data container\n const loadPromises = Object.entries(appDataResponse.data).map(\n async ([tableName, fileRef]) => {\n await this.loadFile(fileRef.file_path, tableName);\n },\n );\n\n await Promise.all(loadPromises);\n\n return appDataResponse.data;\n }\n\n /**\n * Execute a SQL query against loaded data\n *\n * @param sql - SQL query to execute\n * @returns Query result with columns and rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n *\n * const result = await sdk.query('SELECT product, SUM(amount) as total FROM sales GROUP BY product');\n * console.log(result.columns); // ['product', 'total']\n * console.log(result.rows); // [['Product A', 1000], ['Product B', 2000]]\n * console.log(result.rowCount); // 2\n * ```\n */\n async query(sql: string): Promise<QueryResult> {\n return this.reader.query(sql);\n }\n\n /**\n * Get all data from a loaded table\n *\n * @param tableName - Name of the table\n * @param limit - Maximum number of rows (optional)\n * @returns Query result\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const allData = await sdk.getAll('sales');\n * const first100 = await sdk.getAll('sales', 100);\n * ```\n */\n async getAll(tableName: string, limit?: number): Promise<QueryResult> {\n return this.reader.getAll(tableName, limit);\n }\n\n /**\n * Get schema information for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Schema information\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const schema = await sdk.getSchema('sales');\n * console.log(schema.columns); // ['column_name', 'column_type', ...]\n * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]\n * ```\n */\n async getSchema(tableName: string): Promise<QueryResult> {\n return this.reader.getSchema(tableName);\n }\n\n /**\n * Get row count for a loaded table\n *\n * @param tableName - Name of the table\n * @returns Number of rows\n *\n * @example\n * ```typescript\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const count = await sdk.count('sales');\n * console.log(`Total rows: ${count}`);\n * ```\n */\n async count(tableName: string): Promise<number> {\n return this.reader.count(tableName);\n }\n\n /**\n * Get direct access to the underlying OxyClient\n *\n * Useful for advanced operations like listing apps, getting displays, etc.\n *\n * @returns The OxyClient instance\n *\n * @example\n * ```typescript\n * const apps = await sdk.getClient().listApps();\n * const displays = await sdk.getClient().getDisplays('my-app.app.yml');\n * ```\n */\n getClient(): OxyClient {\n return this.client;\n }\n\n /**\n * Get direct access to the underlying ParquetReader\n *\n * Useful for advanced operations like registering blobs directly.\n *\n * @returns The ParquetReader instance\n *\n * @example\n * ```typescript\n * const myBlob = new Blob([parquetData]);\n * await sdk.getReader().registerParquet(myBlob, 'mydata');\n * ```\n */\n getReader(): ParquetReader {\n return this.reader;\n }\n\n /**\n * Close and cleanup all resources\n *\n * This clears all loaded data and releases resources. Call this when you're done with the SDK.\n *\n * @example\n * ```typescript\n * const sdk = new OxySDK({ apiKey: 'key', projectId: 'project' });\n * await sdk.loadFile('data/sales.parquet', 'sales');\n * const result = await sdk.query('SELECT * FROM sales');\n * await sdk.close(); // Clean up\n * ```\n */\n async close(): Promise<void> {\n await this.reader.close();\n }\n}\n","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n ReactNode,\n} from \"react\";\nimport { OxySDK } from \"./sdk\";\nimport { OxyConfig } from \"./config\";\n\n/**\n * Context value provided to child components\n */\nexport interface OxyContextValue {\n sdk: OxySDK | null;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * React context for OxySDK\n */\nconst OxyContext = createContext<OxyContextValue | undefined>(undefined);\n\n/**\n * Props for OxyProvider component\n */\nexport interface OxyProviderProps {\n children: ReactNode;\n config?: Partial<OxyConfig>;\n /**\n * If true, uses async initialization (supports postMessage auth in iframes)\n * If false, uses synchronous initialization with provided config\n */\n useAsync?: boolean;\n /**\n * Optional app path to load initial app data from upon initialization\n */\n appPath?: string;\n /**\n * Optional initial files to preload into the SDK as a mapping of filename to content\n */\n files?: Record<string, string>;\n /**\n * Called when SDK is successfully initialized\n */\n onReady?: (sdk: OxySDK) => void;\n /**\n * Called when initialization fails\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Provider component that initializes and provides OxySDK to child components\n *\n * @example\n * ```tsx\n * // Synchronous initialization with config\n * function App() {\n * return (\n * <OxyProvider config={{\n * apiKey: 'your-key',\n * projectId: 'your-project',\n * baseUrl: 'https://api.oxy.tech'\n * }}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Async initialization (for iframe/postMessage auth)\n * function App() {\n * return (\n * <OxyProvider\n * useAsync\n * config={{ parentOrigin: 'https://app.example.com' }}\n * >\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With environment variables\n * import { createConfig } from '@oxy/sdk';\n *\n * function App() {\n * return (\n * <OxyProvider config={createConfig()}>\n * <Dashboard />\n * </OxyProvider>\n * );\n * }\n * ```\n */\nexport function OxyProvider({\n children,\n config,\n useAsync = false,\n appPath,\n files,\n onReady,\n onError,\n}: OxyProviderProps) {\n const [sdk, setSdk] = useState<OxySDK | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n let mounted = true;\n let sdkInstance: OxySDK | null = null;\n\n async function initializeSDK() {\n try {\n setIsLoading(true);\n setError(null);\n\n if (useAsync) {\n // Async initialization (supports postMessage auth)\n sdkInstance = await OxySDK.create(config);\n if (appPath) {\n await sdkInstance.loadAppData(appPath);\n }\n\n if (files) {\n const fileEntries = Object.entries(files).map(\n ([tableName, filePath]) => ({\n tableName,\n filePath,\n }),\n );\n await sdkInstance.loadFiles(fileEntries);\n }\n } else {\n // Sync initialization with provided config\n if (!config) {\n throw new Error(\n \"Config is required when useAsync is false. Either provide config or set useAsync=true.\",\n );\n }\n sdkInstance = new OxySDK(config as OxyConfig);\n }\n\n if (mounted) {\n setSdk(sdkInstance);\n setIsLoading(false);\n onReady?.(sdkInstance);\n }\n } catch (err) {\n const error =\n err instanceof Error ? err : new Error(\"Failed to initialize SDK\");\n\n if (mounted) {\n setError(error);\n setIsLoading(false);\n onError?.(error);\n }\n }\n }\n\n initializeSDK();\n\n // Cleanup function\n return () => {\n mounted = false;\n if (sdkInstance) {\n sdkInstance.close().catch(console.error);\n }\n };\n }, [config, useAsync, onReady, onError]);\n\n return (\n <OxyContext.Provider value={{ sdk, isLoading, error }}>\n {children}\n </OxyContext.Provider>\n );\n}\n\n/**\n * Hook to access OxySDK from child components\n *\n * @throws {Error} If used outside of OxyProvider\n * @returns {OxyContextValue} The SDK instance, loading state, and error\n *\n * @example\n * ```tsx\n * function Dashboard() {\n * const { sdk, isLoading, error } = useOxy();\n *\n * useEffect(() => {\n * if (sdk) {\n * sdk.loadAppData('dashboard.app.yml')\n * .then(() => sdk.query('SELECT * FROM my_table'))\n * .then(result => console.log(result));\n * }\n * }, [sdk]);\n *\n * if (isLoading) return <div>Loading SDK...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!sdk) return null;\n *\n * return <div>Dashboard</div>;\n * }\n * ```\n */\nexport function useOxy(): OxyContextValue {\n const context = useContext(OxyContext);\n\n if (context === undefined) {\n throw new Error(\"useOxy must be used within an OxyProvider\");\n }\n\n return context;\n}\n\n/**\n * Hook to access OxySDK that throws if not ready\n *\n * This is a convenience hook that returns the SDK directly or throws an error if not initialized.\n * Use this when you know the SDK should be ready.\n *\n * @throws {Error} If used outside of OxyProvider or if SDK is not initialized\n * @returns {OxySDK} The SDK instance\n *\n * @example\n * ```tsx\n * function DataTable() {\n * const sdk = useOxySDK();\n * const [data, setData] = useState(null);\n *\n * useEffect(() => {\n * sdk.loadFile('data.parquet', 'data')\n * .then(() => sdk.query('SELECT * FROM data LIMIT 100'))\n * .then(setData);\n * }, [sdk]);\n *\n * return <table>...</table>;\n * }\n * ```\n */\nexport function useOxySDK(): OxySDK {\n const { sdk, isLoading, error } = useOxy();\n\n if (error) {\n throw error;\n }\n\n if (isLoading || !sdk) {\n throw new Error(\"OxySDK is not yet initialized\");\n }\n\n return sdk;\n}\n"],"mappings":"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"}
|