@inkindcards/semantic-layer 0.2.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,222 @@
1
+ // src/client.ts
2
+ var TOKEN_STORAGE_KEY = "semantic-layer-token";
3
+ var SemanticLayerClient = class {
4
+ constructor(config) {
5
+ this.accessToken = null;
6
+ this.tokenExpiry = 0;
7
+ this.userEmail = null;
8
+ this.metadataCache = null;
9
+ this.metadataCacheTime = 0;
10
+ this.CACHE_TTL_MS = 5 * 60 * 1e3;
11
+ this.authListeners = /* @__PURE__ */ new Set();
12
+ this.admin = {
13
+ listFields: () => this.adminCall("fields.list"),
14
+ createField: (input) => this.adminCall("fields.create", input),
15
+ updateField: (input) => this.adminCall("fields.update", input),
16
+ deleteField: (id) => this.adminCall("fields.delete", { id }),
17
+ listRoles: () => this.adminCall("roles.list"),
18
+ createRole: (input) => this.adminCall("roles.create", input),
19
+ updateRole: (input) => this.adminCall("roles.update", input),
20
+ deleteRole: (id) => this.adminCall("roles.delete", { id }),
21
+ setRoleFields: (role_id, curated_field_ids) => this.adminCall("roles.setFields", { role_id, curated_field_ids }),
22
+ listUsers: () => this.adminCall("users.list"),
23
+ assignUserRole: (input) => this.adminCall("users.assignRole", input),
24
+ removeUserRole: (input) => this.adminCall("users.removeRole", input),
25
+ listUserOverrides: (user_id) => this.adminCall("users.listOverrides", { user_id }),
26
+ setUserOverride: (input) => this.adminCall("users.setOverride", input),
27
+ removeUserOverride: (input) => this.adminCall("users.removeOverride", input)
28
+ };
29
+ this.gatewayUrl = config.gatewayUrl;
30
+ if (typeof window !== "undefined") {
31
+ try {
32
+ const stored = sessionStorage.getItem(TOKEN_STORAGE_KEY);
33
+ if (stored) {
34
+ const parsed = JSON.parse(stored);
35
+ if (parsed.expiresAt > Date.now()) {
36
+ this.accessToken = parsed.token;
37
+ this.tokenExpiry = parsed.expiresAt;
38
+ this.userEmail = parsed.email || null;
39
+ } else {
40
+ sessionStorage.removeItem(TOKEN_STORAGE_KEY);
41
+ }
42
+ }
43
+ } catch {
44
+ }
45
+ }
46
+ }
47
+ // -- Auth ------------------------------------------------------------------
48
+ /**
49
+ * Returns the URL to redirect the browser to for Google sign-in.
50
+ * After the user authenticates, the gateway redirects back to returnUrl
51
+ * with the access token in the URL hash fragment.
52
+ */
53
+ getSignInUrl(returnUrl) {
54
+ const target = returnUrl || (typeof window !== "undefined" ? window.location.href.split("#")[0] : "");
55
+ return `${this.gatewayUrl}/auth/google?returnUrl=${encodeURIComponent(target)}`;
56
+ }
57
+ /**
58
+ * Check the current URL hash for auth tokens (set by the gateway callback redirect).
59
+ * If found, extracts them, stores the session, clears the hash, and returns true.
60
+ */
61
+ handleAuthCallback() {
62
+ if (typeof window === "undefined") return false;
63
+ const hash = window.location.hash.slice(1);
64
+ if (!hash) return false;
65
+ const params = new URLSearchParams(hash);
66
+ const authError = params.get("auth_error");
67
+ if (authError) {
68
+ window.history.replaceState(null, "", window.location.pathname + window.location.search);
69
+ throw new SemanticLayerError(authError, "AUTH_ERROR");
70
+ }
71
+ const accessToken = params.get("access_token");
72
+ const email = params.get("email");
73
+ const expiresIn = parseInt(params.get("expires_in") || "0", 10);
74
+ if (!accessToken || !email) return false;
75
+ window.history.replaceState(null, "", window.location.pathname + window.location.search);
76
+ this.setAccessToken(accessToken, email, expiresIn);
77
+ return true;
78
+ }
79
+ /**
80
+ * Set the Google access token (called after OAuth redirect callback).
81
+ */
82
+ setAccessToken(token, email, expiresIn) {
83
+ this.accessToken = token;
84
+ this.userEmail = email;
85
+ this.tokenExpiry = Date.now() + expiresIn * 1e3;
86
+ if (typeof window !== "undefined") {
87
+ try {
88
+ sessionStorage.setItem(
89
+ TOKEN_STORAGE_KEY,
90
+ JSON.stringify({ token, email, expiresAt: this.tokenExpiry })
91
+ );
92
+ } catch {
93
+ }
94
+ }
95
+ const session = { user: { id: email, email } };
96
+ for (const listener of this.authListeners) {
97
+ listener("SIGNED_IN", session);
98
+ }
99
+ }
100
+ async getSession() {
101
+ if (this.accessToken && Date.now() < this.tokenExpiry) {
102
+ return { user: { id: this.userEmail || "", email: this.userEmail || "" } };
103
+ }
104
+ return null;
105
+ }
106
+ async signOut() {
107
+ this.accessToken = null;
108
+ this.tokenExpiry = 0;
109
+ this.userEmail = null;
110
+ this.metadataCache = null;
111
+ if (typeof window !== "undefined") {
112
+ try {
113
+ sessionStorage.removeItem(TOKEN_STORAGE_KEY);
114
+ } catch {
115
+ }
116
+ }
117
+ for (const listener of this.authListeners) {
118
+ listener("SIGNED_OUT", null);
119
+ }
120
+ return { error: null };
121
+ }
122
+ onAuthStateChange(callback) {
123
+ this.authListeners.add(callback);
124
+ return {
125
+ data: {
126
+ subscription: {
127
+ unsubscribe: () => {
128
+ this.authListeners.delete(callback);
129
+ }
130
+ }
131
+ }
132
+ };
133
+ }
134
+ // -- API calls -------------------------------------------------------------
135
+ async apiCall(path, body) {
136
+ if (!this.accessToken) {
137
+ throw new SemanticLayerError("Not authenticated", "AUTH_ERROR");
138
+ }
139
+ const resp = await fetch(`${this.gatewayUrl}${path}`, {
140
+ method: "POST",
141
+ headers: {
142
+ Authorization: `Bearer ${this.accessToken}`,
143
+ "Content-Type": "application/json"
144
+ },
145
+ body: body !== void 0 ? JSON.stringify(body) : void 0
146
+ });
147
+ const data = await resp.json();
148
+ if (!resp.ok || data?.error) {
149
+ throw new SemanticLayerError(
150
+ data?.error || `Request failed: ${resp.status}`,
151
+ resp.status === 401 ? "AUTH_ERROR" : "API_ERROR"
152
+ );
153
+ }
154
+ return data;
155
+ }
156
+ // -- Metadata --------------------------------------------------------------
157
+ async getMetadata(forceRefresh = false) {
158
+ const now = Date.now();
159
+ if (!forceRefresh && this.metadataCache && now - this.metadataCacheTime < this.CACHE_TTL_MS) {
160
+ return this.metadataCache;
161
+ }
162
+ const data = await this.apiCall("/v1/metadata");
163
+ this.metadataCache = data;
164
+ this.metadataCacheTime = now;
165
+ return data;
166
+ }
167
+ async getMetrics() {
168
+ const { fields } = await this.getMetadata();
169
+ return fields.filter((f) => f.type === "metric");
170
+ }
171
+ async getDimensions() {
172
+ const { fields } = await this.getMetadata();
173
+ return fields.filter((f) => f.type === "dimension" || f.type === "time_dimension");
174
+ }
175
+ async getField(nameOrId) {
176
+ const { fields } = await this.getMetadata();
177
+ return fields.find((f) => f.name === nameOrId || f.id === nameOrId);
178
+ }
179
+ // -- Query -----------------------------------------------------------------
180
+ async query(config) {
181
+ if (config.values.length === 0) {
182
+ return { columns: [], rows: [], totalRows: 0, executionTimeMs: 0 };
183
+ }
184
+ return this.apiCall("/v1/query", { config });
185
+ }
186
+ async simpleQuery(input) {
187
+ const { fields } = await this.getMetadata();
188
+ const fieldMap = new Map(fields.map((f) => [f.name, f]));
189
+ const values = input.metrics.map((name) => {
190
+ const field = fieldMap.get(name);
191
+ if (!field) throw new SemanticLayerError(`Unknown metric: "${name}"`, "UNKNOWN_FIELD");
192
+ return { fieldId: field.id, field };
193
+ });
194
+ const rows = (input.groupBy || []).map((name) => {
195
+ const field = fieldMap.get(name);
196
+ if (!field) throw new SemanticLayerError(`Unknown dimension: "${name}"`, "UNKNOWN_FIELD");
197
+ const grain = field.type === "time_dimension" ? input.grain : void 0;
198
+ return { fieldId: field.id, field, grain };
199
+ });
200
+ const filters = Object.entries(input.filters || {}).map(([name, filterValues]) => {
201
+ const field = fieldMap.get(name);
202
+ if (!field) throw new SemanticLayerError(`Unknown filter field: "${name}"`, "UNKNOWN_FIELD");
203
+ return { fieldId: field.id, field, filterValues };
204
+ });
205
+ return this.query({ values, rows, columns: [], filters });
206
+ }
207
+ // -- Admin -----------------------------------------------------------------
208
+ async adminCall(action, body = {}) {
209
+ return this.apiCall("/v1/admin", { action, ...body });
210
+ }
211
+ };
212
+ var SemanticLayerError = class extends Error {
213
+ constructor(message, code) {
214
+ super(message);
215
+ this.name = "SemanticLayerError";
216
+ this.code = code;
217
+ }
218
+ };
219
+
220
+ export { SemanticLayerClient, SemanticLayerError };
221
+ //# sourceMappingURL=chunk-WR4D3UI6.js.map
222
+ //# sourceMappingURL=chunk-WR4D3UI6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-WR4D3UI6.js","sourcesContent":["import type {\n SemanticLayerConfig,\n MetadataResponse,\n PivotConfig,\n QueryResult,\n SimpleQueryInput,\n SemanticField,\n CuratedField,\n AccessRole,\n UserRoleAssignment,\n UserFieldOverride,\n} from \"./types\";\n\nconst TOKEN_STORAGE_KEY = \"semantic-layer-token\";\n\nexport class SemanticLayerClient {\n readonly gatewayUrl: string;\n private accessToken: string | null = null;\n private tokenExpiry = 0;\n private userEmail: string | null = null;\n private metadataCache: MetadataResponse | null = null;\n private metadataCacheTime = 0;\n private readonly CACHE_TTL_MS = 5 * 60 * 1000;\n private authListeners = new Set<(event: string, session: SessionLike | null) => void>();\n\n constructor(config: SemanticLayerConfig) {\n this.gatewayUrl = config.gatewayUrl;\n\n if (typeof window !== \"undefined\") {\n try {\n const stored = sessionStorage.getItem(TOKEN_STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored);\n if (parsed.expiresAt > Date.now()) {\n this.accessToken = parsed.token;\n this.tokenExpiry = parsed.expiresAt;\n this.userEmail = parsed.email || null;\n } else {\n sessionStorage.removeItem(TOKEN_STORAGE_KEY);\n }\n }\n } catch {\n // Ignore storage errors\n }\n }\n }\n\n // -- Auth ------------------------------------------------------------------\n\n /**\n * Returns the URL to redirect the browser to for Google sign-in.\n * After the user authenticates, the gateway redirects back to returnUrl\n * with the access token in the URL hash fragment.\n */\n getSignInUrl(returnUrl?: string): string {\n const target = returnUrl || (typeof window !== \"undefined\" ? window.location.href.split(\"#\")[0] : \"\");\n return `${this.gatewayUrl}/auth/google?returnUrl=${encodeURIComponent(target)}`;\n }\n\n /**\n * Check the current URL hash for auth tokens (set by the gateway callback redirect).\n * If found, extracts them, stores the session, clears the hash, and returns true.\n */\n handleAuthCallback(): boolean {\n if (typeof window === \"undefined\") return false;\n\n const hash = window.location.hash.slice(1);\n if (!hash) return false;\n\n const params = new URLSearchParams(hash);\n\n const authError = params.get(\"auth_error\");\n if (authError) {\n window.history.replaceState(null, \"\", window.location.pathname + window.location.search);\n throw new SemanticLayerError(authError, \"AUTH_ERROR\");\n }\n\n const accessToken = params.get(\"access_token\");\n const email = params.get(\"email\");\n const expiresIn = parseInt(params.get(\"expires_in\") || \"0\", 10);\n\n if (!accessToken || !email) return false;\n\n window.history.replaceState(null, \"\", window.location.pathname + window.location.search);\n this.setAccessToken(accessToken, email, expiresIn);\n return true;\n }\n\n /**\n * Set the Google access token (called after OAuth redirect callback).\n */\n setAccessToken(token: string, email: string, expiresIn: number) {\n this.accessToken = token;\n this.userEmail = email;\n this.tokenExpiry = Date.now() + expiresIn * 1000;\n\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.setItem(\n TOKEN_STORAGE_KEY,\n JSON.stringify({ token, email, expiresAt: this.tokenExpiry }),\n );\n } catch {\n // Ignore storage errors\n }\n }\n\n const session: SessionLike = { user: { id: email, email } };\n for (const listener of this.authListeners) {\n listener(\"SIGNED_IN\", session);\n }\n }\n\n async getSession(): Promise<SessionLike | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) {\n return { user: { id: this.userEmail || \"\", email: this.userEmail || \"\" } };\n }\n return null;\n }\n\n async signOut() {\n this.accessToken = null;\n this.tokenExpiry = 0;\n this.userEmail = null;\n this.metadataCache = null;\n\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.removeItem(TOKEN_STORAGE_KEY);\n } catch {\n // Ignore storage errors\n }\n }\n\n for (const listener of this.authListeners) {\n listener(\"SIGNED_OUT\", null);\n }\n\n return { error: null };\n }\n\n onAuthStateChange(callback: (event: string, session: SessionLike | null) => void) {\n this.authListeners.add(callback);\n return {\n data: {\n subscription: {\n unsubscribe: () => {\n this.authListeners.delete(callback);\n },\n },\n },\n };\n }\n\n // -- API calls -------------------------------------------------------------\n\n private async apiCall<T>(path: string, body?: unknown): Promise<T> {\n if (!this.accessToken) {\n throw new SemanticLayerError(\"Not authenticated\", \"AUTH_ERROR\");\n }\n\n const resp = await fetch(`${this.gatewayUrl}${path}`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n const data = await resp.json();\n\n if (!resp.ok || data?.error) {\n throw new SemanticLayerError(\n data?.error || `Request failed: ${resp.status}`,\n resp.status === 401 ? \"AUTH_ERROR\" : \"API_ERROR\",\n );\n }\n\n return data as T;\n }\n\n // -- Metadata --------------------------------------------------------------\n\n async getMetadata(forceRefresh = false): Promise<MetadataResponse> {\n const now = Date.now();\n if (!forceRefresh && this.metadataCache && now - this.metadataCacheTime < this.CACHE_TTL_MS) {\n return this.metadataCache;\n }\n\n const data = await this.apiCall<MetadataResponse>(\"/v1/metadata\");\n this.metadataCache = data;\n this.metadataCacheTime = now;\n return data;\n }\n\n async getMetrics(): Promise<SemanticField[]> {\n const { fields } = await this.getMetadata();\n return fields.filter((f) => f.type === \"metric\");\n }\n\n async getDimensions(): Promise<SemanticField[]> {\n const { fields } = await this.getMetadata();\n return fields.filter((f) => f.type === \"dimension\" || f.type === \"time_dimension\");\n }\n\n async getField(nameOrId: string): Promise<SemanticField | undefined> {\n const { fields } = await this.getMetadata();\n return fields.find((f) => f.name === nameOrId || f.id === nameOrId);\n }\n\n // -- Query -----------------------------------------------------------------\n\n async query(config: PivotConfig): Promise<QueryResult> {\n if (config.values.length === 0) {\n return { columns: [], rows: [], totalRows: 0, executionTimeMs: 0 };\n }\n return this.apiCall<QueryResult>(\"/v1/query\", { config });\n }\n\n async simpleQuery(input: SimpleQueryInput): Promise<QueryResult> {\n const { fields } = await this.getMetadata();\n const fieldMap = new Map(fields.map((f) => [f.name, f]));\n\n const values = input.metrics.map((name) => {\n const field = fieldMap.get(name);\n if (!field) throw new SemanticLayerError(`Unknown metric: \"${name}\"`, \"UNKNOWN_FIELD\");\n return { fieldId: field.id, field };\n });\n\n const rows = (input.groupBy || []).map((name) => {\n const field = fieldMap.get(name);\n if (!field) throw new SemanticLayerError(`Unknown dimension: \"${name}\"`, \"UNKNOWN_FIELD\");\n const grain = field.type === \"time_dimension\" ? input.grain : undefined;\n return { fieldId: field.id, field, grain };\n });\n\n const filters = Object.entries(input.filters || {}).map(([name, filterValues]) => {\n const field = fieldMap.get(name);\n if (!field) throw new SemanticLayerError(`Unknown filter field: \"${name}\"`, \"UNKNOWN_FIELD\");\n return { fieldId: field.id, field, filterValues };\n });\n\n return this.query({ values, rows, columns: [], filters });\n }\n\n // -- Admin -----------------------------------------------------------------\n\n private async adminCall<T>(action: string, body: Record<string, unknown> = {}): Promise<T> {\n return this.apiCall<T>(\"/v1/admin\", { action, ...body });\n }\n\n readonly admin = {\n listFields: () => this.adminCall<{ fields: CuratedField[] }>(\"fields.list\"),\n createField: (input: { field_name: string; field_type: string; display_name?: string; description?: string }) =>\n this.adminCall<{ field: CuratedField }>(\"fields.create\", input),\n updateField: (input: { id: number; field_name?: string; display_name?: string; description?: string; is_active?: boolean }) =>\n this.adminCall<{ field: CuratedField }>(\"fields.update\", input),\n deleteField: (id: number) =>\n this.adminCall<{ deleted: boolean }>(\"fields.delete\", { id }),\n\n listRoles: () => this.adminCall<{ roles: AccessRole[] }>(\"roles.list\"),\n createRole: (input: { name: string; description?: string; is_default?: boolean }) =>\n this.adminCall<{ role: AccessRole }>(\"roles.create\", input),\n updateRole: (input: { id: number; name?: string; description?: string; is_default?: boolean }) =>\n this.adminCall<{ role: AccessRole }>(\"roles.update\", input),\n deleteRole: (id: number) =>\n this.adminCall<{ deleted: boolean }>(\"roles.delete\", { id }),\n setRoleFields: (role_id: number, curated_field_ids: number[]) =>\n this.adminCall<{ role_id: number; field_count: number }>(\"roles.setFields\", { role_id, curated_field_ids }),\n\n listUsers: () => this.adminCall<{ users: UserRoleAssignment[] }>(\"users.list\"),\n assignUserRole: (input: { email: string; role_id: number; is_admin?: boolean }) =>\n this.adminCall<{ assignment: UserRoleAssignment }>(\"users.assignRole\", input),\n removeUserRole: (input: { email: string; role_id: number }) =>\n this.adminCall<{ deleted: boolean }>(\"users.removeRole\", input),\n\n listUserOverrides: (user_id: string) =>\n this.adminCall<{ overrides: UserFieldOverride[] }>(\"users.listOverrides\", { user_id }),\n setUserOverride: (input: { user_id: string; curated_field_id: number; access: \"grant\" | \"deny\" }) =>\n this.adminCall<{ override: UserFieldOverride }>(\"users.setOverride\", input),\n removeUserOverride: (input: { user_id: string; curated_field_id: number }) =>\n this.adminCall<{ deleted: boolean }>(\"users.removeOverride\", input),\n };\n}\n\nexport interface SessionLike {\n user: { id: string; email: string };\n}\n\nexport class SemanticLayerError extends Error {\n code: string;\n constructor(message: string, code: string) {\n super(message);\n this.name = \"SemanticLayerError\";\n this.code = code;\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSHHZ37FE_cjs = require('./chunk-SHHZ37FE.cjs');
3
+ var chunkT2C43AAL_cjs = require('./chunk-T2C43AAL.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
@@ -56,7 +56,7 @@ function MetricPicker({
56
56
  searchPlaceholder = "Search metrics and dimensions...",
57
57
  className
58
58
  }) {
59
- const { fields, categories, isLoading, error } = chunkSHHZ37FE_cjs.useMetrics();
59
+ const { fields, categories, isLoading, error } = chunkT2C43AAL_cjs.useMetrics();
60
60
  const [search, setSearch] = react.useState("");
61
61
  const filtered = react.useMemo(() => {
62
62
  let result = fields;
@@ -312,7 +312,7 @@ var emptyStyle = {
312
312
  fontSize: 14
313
313
  };
314
314
  function DataCatalog({ className, showCopyButton = true, fieldTypes }) {
315
- const { fields, metrics, dimensions, isLoading, error } = chunkSHHZ37FE_cjs.useMetrics();
315
+ const { fields, metrics, dimensions, isLoading, error } = chunkT2C43AAL_cjs.useMetrics();
316
316
  const [search, setSearch] = react.useState("");
317
317
  const [typeFilter, setTypeFilter] = react.useState("all");
318
318
  const [copiedField, setCopiedField] = react.useState(null);
@@ -522,7 +522,7 @@ var emptyStyle2 = {
522
522
  fontSize: 14
523
523
  };
524
524
  function FieldsTab() {
525
- const { fields, isLoading, error, createField, updateField, deleteField } = chunkSHHZ37FE_cjs.useAdminFields();
525
+ const { fields, isLoading, error, createField, updateField, deleteField } = chunkT2C43AAL_cjs.useAdminFields();
526
526
  const [showAdd, setShowAdd] = react.useState(false);
527
527
  const [newName, setNewName] = react.useState("");
528
528
  const [newType, setNewType] = react.useState("metric");
@@ -611,8 +611,8 @@ function FieldsTab() {
611
611
  ] });
612
612
  }
613
613
  function RolesTab() {
614
- const { roles, isLoading, error, createRole, deleteRole, setRoleFields } = chunkSHHZ37FE_cjs.useAdminRoles();
615
- const { fields } = chunkSHHZ37FE_cjs.useAdminFields();
614
+ const { roles, isLoading, error, createRole, deleteRole, setRoleFields } = chunkT2C43AAL_cjs.useAdminRoles();
615
+ const { fields } = chunkT2C43AAL_cjs.useAdminFields();
616
616
  const [showAdd, setShowAdd] = react.useState(false);
617
617
  const [newName, setNewName] = react.useState("");
618
618
  const [newDesc, setNewDesc] = react.useState("");
@@ -699,8 +699,8 @@ function RolesTab() {
699
699
  ] });
700
700
  }
701
701
  function UsersTab() {
702
- const { users, isLoading, error, assignUserRole, removeUserRole } = chunkSHHZ37FE_cjs.useAdminUsers();
703
- const { roles } = chunkSHHZ37FE_cjs.useAdminRoles();
702
+ const { users, isLoading, error, assignUserRole, removeUserRole } = chunkT2C43AAL_cjs.useAdminUsers();
703
+ const { roles } = chunkT2C43AAL_cjs.useAdminRoles();
704
704
  const [showAdd, setShowAdd] = react.useState(false);
705
705
  const [newEmail, setNewEmail] = react.useState("");
706
706
  const [newRoleId, setNewRoleId] = react.useState(0);
@@ -787,7 +787,7 @@ function UsersTab() {
787
787
  ] });
788
788
  }
789
789
  function AdminDashboard({ className }) {
790
- const { isAuthenticated, isLoading: authLoading } = chunkSHHZ37FE_cjs.useAuth();
790
+ const { isAuthenticated, isLoading: authLoading } = chunkT2C43AAL_cjs.useAuth();
791
791
  const [tab, setTab] = react.useState("fields");
792
792
  const [initError, setInitError] = react.useState(null);
793
793
  if (authLoading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...rootStyle2, ...emptyStyle2 }, children: "Loading..." });
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { S as SemanticField, F as FieldType, Q as QueryResult } from './types-Dc8Zdacw.cjs';
2
+ import { S as SemanticField, F as FieldType, Q as QueryResult } from './types-DJpYLOyy.cjs';
3
3
 
4
4
  interface MetricPickerProps {
5
5
  onSelect: (field: SemanticField) => void;
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { S as SemanticField, F as FieldType, Q as QueryResult } from './types-Dc8Zdacw.js';
2
+ import { S as SemanticField, F as FieldType, Q as QueryResult } from './types-DJpYLOyy.js';
3
3
 
4
4
  interface MetricPickerProps {
5
5
  onSelect: (field: SemanticField) => void;
@@ -1,4 +1,4 @@
1
- import { useMetrics, useAuth, useAdminFields, useAdminRoles, useAdminUsers } from './chunk-SLRBAF37.js';
1
+ import { useMetrics, useAuth, useAdminFields, useAdminRoles, useAdminUsers } from './chunk-3OR3QCN6.js';
2
2
  import { useState, useMemo, useCallback } from 'react';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
 
package/dist/index.cjs CHANGED
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var chunkB23E3XFB_cjs = require('./chunk-B23E3XFB.cjs');
3
+ var chunkW64RGDXH_cjs = require('./chunk-W64RGDXH.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "SemanticLayerClient", {
8
8
  enumerable: true,
9
- get: function () { return chunkB23E3XFB_cjs.SemanticLayerClient; }
9
+ get: function () { return chunkW64RGDXH_cjs.SemanticLayerClient; }
10
10
  });
11
11
  Object.defineProperty(exports, "SemanticLayerError", {
12
12
  enumerable: true,
13
- get: function () { return chunkB23E3XFB_cjs.SemanticLayerError; }
13
+ get: function () { return chunkW64RGDXH_cjs.SemanticLayerError; }
14
14
  });
15
15
  //# sourceMappingURL=index.cjs.map
16
16
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -1,57 +1,48 @@
1
- import * as _supabase_auth_js from '@supabase/auth-js';
2
- import { SupabaseClient, Session } from '@supabase/supabase-js';
3
- import { e as SemanticLayerConfig, M as MetadataResponse, S as SemanticField, P as PivotConfig, Q as QueryResult, b as SimpleQueryInput, C as CuratedField, A as AccessRole, U as UserRoleAssignment, c as UserFieldOverride } from './types-Dc8Zdacw.cjs';
4
- export { f as AggregationType, d as AuthState, D as DataType, a as FieldCategory, F as FieldType, g as PivotField, h as QueryColumn, T as TimeGrain } from './types-Dc8Zdacw.cjs';
1
+ import { e as SemanticLayerConfig, M as MetadataResponse, S as SemanticField, P as PivotConfig, Q as QueryResult, b as SimpleQueryInput, C as CuratedField, A as AccessRole, U as UserRoleAssignment, c as UserFieldOverride } from './types-DJpYLOyy.cjs';
2
+ export { f as AggregationType, d as AuthState, D as DataType, a as FieldCategory, F as FieldType, g as PivotField, h as QueryColumn, T as TimeGrain } from './types-DJpYLOyy.cjs';
5
3
 
6
4
  declare class SemanticLayerClient {
7
- private supabase;
5
+ readonly gatewayUrl: string;
6
+ private accessToken;
7
+ private tokenExpiry;
8
+ private userEmail;
8
9
  private metadataCache;
9
10
  private metadataCacheTime;
10
11
  private readonly CACHE_TTL_MS;
11
- readonly gatewayUrl: string;
12
+ private authListeners;
12
13
  constructor(config: SemanticLayerConfig);
13
- /** Access the underlying Supabase client (for auth operations). */
14
- getSupabaseClient(): SupabaseClient;
15
- signInWithGoogle(redirectTo?: string): Promise<_supabase_auth_js.OAuthResponse>;
16
- /** Get the Google sign-in URL without triggering a redirect (for popup flows). */
17
- getSignInUrl(redirectTo?: string): Promise<string | null>;
18
- /** Send a one-time code to the given email (for iframe/editor sign-in). */
19
- sendOtp(email: string): Promise<_supabase_auth_js.AuthOtpResponse>;
20
- /** Verify a one-time code received via email. */
21
- verifyOtp(email: string, token: string): Promise<_supabase_auth_js.AuthResponse>;
14
+ /**
15
+ * Returns the URL to redirect the browser to for Google sign-in.
16
+ * After the user authenticates, the gateway redirects back to returnUrl
17
+ * with the access token in the URL hash fragment.
18
+ */
19
+ getSignInUrl(returnUrl?: string): string;
20
+ /**
21
+ * Check the current URL hash for auth tokens (set by the gateway callback redirect).
22
+ * If found, extracts them, stores the session, clears the hash, and returns true.
23
+ */
24
+ handleAuthCallback(): boolean;
25
+ /**
26
+ * Set the Google access token (called after OAuth redirect callback).
27
+ */
28
+ setAccessToken(token: string, email: string, expiresIn: number): void;
29
+ getSession(): Promise<SessionLike | null>;
22
30
  signOut(): Promise<{
23
- error: _supabase_auth_js.AuthError | null;
31
+ error: null;
24
32
  }>;
25
- getSession(): Promise<Session | null>;
26
- onAuthStateChange(callback: (event: string, session: Session | null) => void): {
33
+ onAuthStateChange(callback: (event: string, session: SessionLike | null) => void): {
27
34
  data: {
28
- subscription: _supabase_auth_js.Subscription;
35
+ subscription: {
36
+ unsubscribe: () => void;
37
+ };
29
38
  };
30
39
  };
31
- /** Set an existing session (used by the popup OAuth callback). */
32
- setSession(accessToken: string, refreshToken: string): Promise<_supabase_auth_js.AuthResponse>;
33
- /**
34
- * Open Google OAuth in a popup window and wait for the callback.
35
- * Uses the auth-callback edge function to relay tokens via postMessage.
36
- */
37
- signInWithPopup(): Promise<void>;
38
- /**
39
- * Fetch the curated catalog of metrics and dimensions from the gateway.
40
- * Results are cached for 5 minutes.
41
- */
40
+ private apiCall;
42
41
  getMetadata(forceRefresh?: boolean): Promise<MetadataResponse>;
43
- /** Get only metrics from the catalog. */
44
42
  getMetrics(): Promise<SemanticField[]>;
45
- /** Get only dimensions (including time dimensions) from the catalog. */
46
43
  getDimensions(): Promise<SemanticField[]>;
47
- /** Find a field by name or id. */
48
44
  getField(nameOrId: string): Promise<SemanticField | undefined>;
49
- /** Execute a query using the full PivotConfig format. */
50
45
  query(config: PivotConfig): Promise<QueryResult>;
51
- /**
52
- * Execute a query using the simplified input format.
53
- * Automatically resolves metric/dimension names to full field objects.
54
- */
55
46
  simpleQuery(input: SimpleQueryInput): Promise<QueryResult>;
56
47
  private adminCall;
57
48
  readonly admin: {
@@ -137,9 +128,15 @@ declare class SemanticLayerClient {
137
128
  }>;
138
129
  };
139
130
  }
131
+ interface SessionLike {
132
+ user: {
133
+ id: string;
134
+ email: string;
135
+ };
136
+ }
140
137
  declare class SemanticLayerError extends Error {
141
138
  code: string;
142
139
  constructor(message: string, code: string);
143
140
  }
144
141
 
145
- export { AccessRole, CuratedField, MetadataResponse, PivotConfig, QueryResult, SemanticField, SemanticLayerClient, SemanticLayerConfig, SemanticLayerError, SimpleQueryInput, UserFieldOverride, UserRoleAssignment };
142
+ export { AccessRole, CuratedField, MetadataResponse, PivotConfig, QueryResult, SemanticField, SemanticLayerClient, SemanticLayerConfig, SemanticLayerError, type SessionLike, SimpleQueryInput, UserFieldOverride, UserRoleAssignment };
package/dist/index.d.ts CHANGED
@@ -1,57 +1,48 @@
1
- import * as _supabase_auth_js from '@supabase/auth-js';
2
- import { SupabaseClient, Session } from '@supabase/supabase-js';
3
- import { e as SemanticLayerConfig, M as MetadataResponse, S as SemanticField, P as PivotConfig, Q as QueryResult, b as SimpleQueryInput, C as CuratedField, A as AccessRole, U as UserRoleAssignment, c as UserFieldOverride } from './types-Dc8Zdacw.js';
4
- export { f as AggregationType, d as AuthState, D as DataType, a as FieldCategory, F as FieldType, g as PivotField, h as QueryColumn, T as TimeGrain } from './types-Dc8Zdacw.js';
1
+ import { e as SemanticLayerConfig, M as MetadataResponse, S as SemanticField, P as PivotConfig, Q as QueryResult, b as SimpleQueryInput, C as CuratedField, A as AccessRole, U as UserRoleAssignment, c as UserFieldOverride } from './types-DJpYLOyy.js';
2
+ export { f as AggregationType, d as AuthState, D as DataType, a as FieldCategory, F as FieldType, g as PivotField, h as QueryColumn, T as TimeGrain } from './types-DJpYLOyy.js';
5
3
 
6
4
  declare class SemanticLayerClient {
7
- private supabase;
5
+ readonly gatewayUrl: string;
6
+ private accessToken;
7
+ private tokenExpiry;
8
+ private userEmail;
8
9
  private metadataCache;
9
10
  private metadataCacheTime;
10
11
  private readonly CACHE_TTL_MS;
11
- readonly gatewayUrl: string;
12
+ private authListeners;
12
13
  constructor(config: SemanticLayerConfig);
13
- /** Access the underlying Supabase client (for auth operations). */
14
- getSupabaseClient(): SupabaseClient;
15
- signInWithGoogle(redirectTo?: string): Promise<_supabase_auth_js.OAuthResponse>;
16
- /** Get the Google sign-in URL without triggering a redirect (for popup flows). */
17
- getSignInUrl(redirectTo?: string): Promise<string | null>;
18
- /** Send a one-time code to the given email (for iframe/editor sign-in). */
19
- sendOtp(email: string): Promise<_supabase_auth_js.AuthOtpResponse>;
20
- /** Verify a one-time code received via email. */
21
- verifyOtp(email: string, token: string): Promise<_supabase_auth_js.AuthResponse>;
14
+ /**
15
+ * Returns the URL to redirect the browser to for Google sign-in.
16
+ * After the user authenticates, the gateway redirects back to returnUrl
17
+ * with the access token in the URL hash fragment.
18
+ */
19
+ getSignInUrl(returnUrl?: string): string;
20
+ /**
21
+ * Check the current URL hash for auth tokens (set by the gateway callback redirect).
22
+ * If found, extracts them, stores the session, clears the hash, and returns true.
23
+ */
24
+ handleAuthCallback(): boolean;
25
+ /**
26
+ * Set the Google access token (called after OAuth redirect callback).
27
+ */
28
+ setAccessToken(token: string, email: string, expiresIn: number): void;
29
+ getSession(): Promise<SessionLike | null>;
22
30
  signOut(): Promise<{
23
- error: _supabase_auth_js.AuthError | null;
31
+ error: null;
24
32
  }>;
25
- getSession(): Promise<Session | null>;
26
- onAuthStateChange(callback: (event: string, session: Session | null) => void): {
33
+ onAuthStateChange(callback: (event: string, session: SessionLike | null) => void): {
27
34
  data: {
28
- subscription: _supabase_auth_js.Subscription;
35
+ subscription: {
36
+ unsubscribe: () => void;
37
+ };
29
38
  };
30
39
  };
31
- /** Set an existing session (used by the popup OAuth callback). */
32
- setSession(accessToken: string, refreshToken: string): Promise<_supabase_auth_js.AuthResponse>;
33
- /**
34
- * Open Google OAuth in a popup window and wait for the callback.
35
- * Uses the auth-callback edge function to relay tokens via postMessage.
36
- */
37
- signInWithPopup(): Promise<void>;
38
- /**
39
- * Fetch the curated catalog of metrics and dimensions from the gateway.
40
- * Results are cached for 5 minutes.
41
- */
40
+ private apiCall;
42
41
  getMetadata(forceRefresh?: boolean): Promise<MetadataResponse>;
43
- /** Get only metrics from the catalog. */
44
42
  getMetrics(): Promise<SemanticField[]>;
45
- /** Get only dimensions (including time dimensions) from the catalog. */
46
43
  getDimensions(): Promise<SemanticField[]>;
47
- /** Find a field by name or id. */
48
44
  getField(nameOrId: string): Promise<SemanticField | undefined>;
49
- /** Execute a query using the full PivotConfig format. */
50
45
  query(config: PivotConfig): Promise<QueryResult>;
51
- /**
52
- * Execute a query using the simplified input format.
53
- * Automatically resolves metric/dimension names to full field objects.
54
- */
55
46
  simpleQuery(input: SimpleQueryInput): Promise<QueryResult>;
56
47
  private adminCall;
57
48
  readonly admin: {
@@ -137,9 +128,15 @@ declare class SemanticLayerClient {
137
128
  }>;
138
129
  };
139
130
  }
131
+ interface SessionLike {
132
+ user: {
133
+ id: string;
134
+ email: string;
135
+ };
136
+ }
140
137
  declare class SemanticLayerError extends Error {
141
138
  code: string;
142
139
  constructor(message: string, code: string);
143
140
  }
144
141
 
145
- export { AccessRole, CuratedField, MetadataResponse, PivotConfig, QueryResult, SemanticField, SemanticLayerClient, SemanticLayerConfig, SemanticLayerError, SimpleQueryInput, UserFieldOverride, UserRoleAssignment };
142
+ export { AccessRole, CuratedField, MetadataResponse, PivotConfig, QueryResult, SemanticField, SemanticLayerClient, SemanticLayerConfig, SemanticLayerError, type SessionLike, SimpleQueryInput, UserFieldOverride, UserRoleAssignment };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { SemanticLayerClient, SemanticLayerError } from './chunk-WPK37LJ6.js';
1
+ export { SemanticLayerClient, SemanticLayerError } from './chunk-WR4D3UI6.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map