@bonnard/sdk
Advanced tools
| "use strict";var Bonnard=(()=>{var m=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var w=(e,r)=>{for(var s in r)m(e,s,{get:r[s],enumerable:!0})},R=(e,r,s,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of b(r))!h.call(e,i)&&i!==s&&m(e,i,{get:()=>r[i],enumerable:!(a=f(r,i))||a.enumerable});return e};var T=e=>R(m({},"__esModule",{value:!0}),e);var Q={};w(Q,{createClient:()=>d,toCubeQuery:()=>l});function l(e){let r={};return e.measures&&(r.measures=e.measures),e.dimensions&&(r.dimensions=e.dimensions),e.filters&&(r.filters=e.filters.map(s=>({member:s.dimension,operator:s.operator,values:s.values}))),e.timeDimension&&(r.timeDimensions=[{dimension:e.timeDimension.dimension,granularity:e.timeDimension.granularity,dateRange:e.timeDimension.dateRange}]),e.orderBy&&(r.order=Object.entries(e.orderBy).map(([s,a])=>[s,a])),e.limit&&(r.limit=e.limit),r}function g(e){try{let r=e.split(".");if(r.length!==3)return 0;let s=r[1].replace(/-/g,"+").replace(/_/g,"/"),a=JSON.parse(atob(s));return typeof a.exp=="number"?a.exp*1e3:0}catch{return 0}}var D=6e4;function d(e){let r=e.baseUrl||"https://app.bonnard.dev",s=null,a=0;async function i(){if(e.apiKey)return e.apiKey;if(e.fetchToken){let t=Date.now();if(s&&a-D>t)return s;let n=await e.fetchToken();return s=n,a=g(n),n}throw new Error("BonnardConfig requires either apiKey or fetchToken")}async function y(t,n){let o=await i(),u=await fetch(`${r}${t}`,{method:"POST",headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!u.ok){let p=await u.json().catch(()=>({error:u.statusText}));throw new Error(p.error||"Query failed")}return u.json()}async function c(t){let n=await i(),o=await fetch(`${r}${t}`,{method:"GET",headers:{Authorization:`Bearer ${n}`}});if(!o.ok){let u=await o.json().catch(()=>({error:o.statusText}));throw new Error(u.error||"Request failed")}return o.json()}return{async query(t){let n=l(t),o=await y("/api/cube/query",{query:n});return{data:o.data,annotation:o.annotation}},async rawQuery(t){let n=await y("/api/cube/query",{query:t});return{data:n.data,annotation:n.annotation}},async sql(t){return y("/api/cube/query",{sql:t})},async explore(t){let n=await c("/api/cube/meta");return t?.viewsOnly??!0?{cubes:n.cubes.filter(u=>u.type==="view")}:n},async getDashboard(t){return c(`/api/dashboards/${encodeURIComponent(t)}`)},async listDashboards(){return c("/api/dashboards")},async docs(t){let n=new URLSearchParams;t?.topic?n.set("topic",t.topic):t?.category&&n.set("category",t.category);let o=n.toString();return c(`/api/docs${o?`?${o}`:""}`)}}}return T(Q);})(); | ||
| //# sourceMappingURL=bonnard.iife.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/browser.ts", "../src/query.ts", "../src/client.ts"], | ||
| "sourcesContent": ["export { createClient } from './client.js';\nexport { toCubeQuery } from './query.js';\n", "/**\n * Bonnard SDK \u2014 Query format conversion (zero IO)\n */\n\nimport type { QueryOptions } from './types.js';\n\n/**\n * Convert SDK QueryOptions into a Cube-native query object.\n * All field names must be fully qualified (e.g. \"orders.revenue\").\n */\nexport function toCubeQuery(options: QueryOptions): Record<string, unknown> {\n const cubeQuery: Record<string, unknown> = {};\n\n if (options.measures) {\n cubeQuery.measures = options.measures;\n }\n\n if (options.dimensions) {\n cubeQuery.dimensions = options.dimensions;\n }\n\n if (options.filters) {\n cubeQuery.filters = options.filters.map(f => ({\n member: f.dimension,\n operator: f.operator,\n values: f.values,\n }));\n }\n\n if (options.timeDimension) {\n cubeQuery.timeDimensions = [{\n dimension: options.timeDimension.dimension,\n granularity: options.timeDimension.granularity,\n dateRange: options.timeDimension.dateRange,\n }];\n }\n\n if (options.orderBy) {\n cubeQuery.order = Object.entries(options.orderBy).map(([key, dir]) => [key, dir]);\n }\n\n if (options.limit) {\n cubeQuery.limit = options.limit;\n }\n\n return cubeQuery;\n}\n", "/**\n * Bonnard SDK \u2014 Client for querying semantic layer\n */\n\nimport type {\n BonnardConfig,\n QueryOptions,\n QueryResult,\n SqlResult,\n CubeQuery,\n ExploreMeta,\n ExploreOptions,\n DashboardResult,\n DashboardListResult,\n DocsOptions,\n DocsTopicListResult,\n DocsTopicResult,\n} from './types.js';\nimport { toCubeQuery } from './query.js';\n\n/**\n * Parse JWT expiry from the payload (base64url-decoded middle segment).\n * Returns the `exp` claim as a millisecond timestamp, or 0 if unparseable.\n */\nfunction parseJwtExpiry(token: string): number {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return 0;\n // base64url \u2192 base64 \u2192 decode\n const payload = parts[1]!.replace(/-/g, '+').replace(/_/g, '/');\n const json = JSON.parse(atob(payload));\n return typeof json.exp === 'number' ? json.exp * 1000 : 0;\n } catch {\n return 0;\n }\n}\n\nconst REFRESH_BUFFER_MS = 60_000; // refresh 60s before expiry\n\nexport function createClient(config: BonnardConfig) {\n const baseUrl = config.baseUrl || 'https://app.bonnard.dev';\n\n // Token cache for fetchToken mode\n let cachedToken: string | null = null;\n let cachedExpiry = 0;\n\n async function getToken(): Promise<string> {\n // Static API key \u2014 return directly\n if (config.apiKey) {\n return config.apiKey;\n }\n\n // Token callback \u2014 cache and refresh\n if (config.fetchToken) {\n const now = Date.now();\n if (cachedToken && cachedExpiry - REFRESH_BUFFER_MS > now) {\n return cachedToken;\n }\n\n const token = await config.fetchToken();\n cachedToken = token;\n cachedExpiry = parseJwtExpiry(token);\n return token;\n }\n\n throw new Error('BonnardConfig requires either apiKey or fetchToken');\n }\n\n async function request<T>(endpoint: string, body: unknown): Promise<T> {\n const token = await getToken();\n const res = await fetch(`${baseUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ error: res.statusText }));\n throw new Error(error.error || 'Query failed');\n }\n\n return res.json();\n }\n\n async function requestGet<T>(endpoint: string): Promise<T> {\n const token = await getToken();\n const res = await fetch(`${baseUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Authorization': `Bearer ${token}`,\n },\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ error: res.statusText }));\n throw new Error(error.error || 'Request failed');\n }\n\n return res.json();\n }\n\n return {\n /**\n * Execute a JSON query against the semantic layer.\n * All field names must be fully qualified (e.g. \"orders.revenue\").\n */\n async query<T = Record<string, unknown>>(options: QueryOptions): Promise<QueryResult<T>> {\n const cubeQuery = toCubeQuery(options);\n\n const result = await request<{ data: T[]; annotation?: QueryResult['annotation'] }>(\n '/api/cube/query',\n { query: cubeQuery }\n );\n\n return { data: result.data, annotation: result.annotation };\n },\n\n /**\n * Execute a raw Cube-native JSON query against the semantic layer.\n * Use this when you already have a Cube API query object.\n */\n async rawQuery<T = Record<string, unknown>>(cubeQuery: CubeQuery): Promise<QueryResult<T>> {\n const result = await request<{ data: T[]; annotation?: QueryResult['annotation'] }>(\n '/api/cube/query',\n { query: cubeQuery }\n );\n\n return { data: result.data, annotation: result.annotation };\n },\n\n /**\n * Execute a SQL query against the semantic layer\n */\n async sql<T = Record<string, unknown>>(query: string): Promise<SqlResult<T>> {\n return request<SqlResult<T>>('/api/cube/query', { sql: query });\n },\n\n /**\n * Discover available cubes, measures, dimensions, and segments.\n * By default returns only views (viewsOnly: true).\n */\n async explore(options?: ExploreOptions): Promise<ExploreMeta> {\n const meta = await requestGet<{ cubes: ExploreMeta['cubes'] }>('/api/cube/meta');\n const viewsOnly = options?.viewsOnly ?? true;\n\n if (viewsOnly) {\n return { cubes: meta.cubes.filter(c => c.type === 'view') };\n }\n\n return meta;\n },\n\n /**\n * Fetch a single dashboard by slug.\n */\n async getDashboard(slug: string): Promise<DashboardResult> {\n return requestGet<DashboardResult>(`/api/dashboards/${encodeURIComponent(slug)}`);\n },\n\n /**\n * List all dashboards for the current organization.\n */\n async listDashboards(): Promise<DashboardListResult> {\n return requestGet<DashboardListResult>('/api/dashboards');\n },\n\n /**\n * Access Bonnard documentation.\n * - `docs()` \u2014 list all topics\n * - `docs({ category: 'dashboards' })` \u2014 list topics in a category\n * - `docs({ topic: 'dashboards.components' })` \u2014 get full markdown content\n */\n async docs(options?: DocsOptions): Promise<DocsTopicListResult | DocsTopicResult> {\n const params = new URLSearchParams();\n if (options?.topic) params.set('topic', options.topic);\n else if (options?.category) params.set('category', options.category);\n const qs = params.toString();\n return requestGet(`/api/docs${qs ? `?${qs}` : ''}`);\n },\n };\n}\n"], | ||
| "mappings": "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", | ||
| "names": ["browser_exports", "__export", "createClient", "toCubeQuery", "toCubeQuery", "options", "cubeQuery", "f", "key", "dir", "parseJwtExpiry", "token", "parts", "payload", "json", "REFRESH_BUFFER_MS", "createClient", "config", "baseUrl", "cachedToken", "cachedExpiry", "getToken", "now", "request", "endpoint", "body", "res", "error", "requestGet", "options", "cubeQuery", "toCubeQuery", "result", "query", "meta", "c", "slug", "params", "qs"] | ||
| } |
| export { createClient } from './client.js'; | ||
| export { toCubeQuery } from './query.js'; |
| export { createClient } from './client.js'; | ||
| export { toCubeQuery } from './query.js'; |
+8
-2
| { | ||
| "name": "@bonnard/sdk", | ||
| "version": "0.4.0", | ||
| "version": "0.4.1", | ||
| "description": "Bonnard SDK - query your semantic layer from any JavaScript or TypeScript app", | ||
@@ -12,4 +12,9 @@ "type": "module", | ||
| "types": "./dist/index.d.ts" | ||
| }, | ||
| "./browser": { | ||
| "default": "./dist/bonnard.iife.js" | ||
| } | ||
| }, | ||
| "unpkg": "dist/bonnard.iife.js", | ||
| "jsdelivr": "dist/bonnard.iife.js", | ||
| "files": [ | ||
@@ -19,3 +24,3 @@ "dist" | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "build": "tsc && esbuild src/browser.ts --bundle --format=iife --global-name=Bonnard --outfile=dist/bonnard.iife.js --minify --sourcemap --target=es2020", | ||
| "dev": "tsc --watch" | ||
@@ -25,2 +30,3 @@ }, | ||
| "devDependencies": { | ||
| "esbuild": "^0.24.0", | ||
| "typescript": "^5.3.3" | ||
@@ -27,0 +33,0 @@ }, |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
30512
79.88%15
36.36%389
4.29%2
100%3
50%4
100%