@everscribe/components-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,634 @@
1
+ // src/api.ts
2
+ var EmbedError = class extends Error {
3
+ constructor(info) {
4
+ super(info.message ?? info.kind);
5
+ this.name = "EmbedError";
6
+ this.kind = info.kind;
7
+ this.status = info.status;
8
+ this.retryAfterMs = info.retryAfterMs;
9
+ }
10
+ };
11
+ async function listEvents(opts) {
12
+ const url = new URL(joinUrl(opts.apiBase, "events"));
13
+ applyListParams(url, opts.params);
14
+ return request(url, opts);
15
+ }
16
+ function applyListParams(url, p) {
17
+ if (!p) return;
18
+ if (p.limit !== void 0) url.searchParams.set("limit", String(p.limit));
19
+ if (p.cursor) url.searchParams.set("cursor", p.cursor);
20
+ if (p.since) url.searchParams.set("since", p.since);
21
+ if (p.before) url.searchParams.set("before", p.before);
22
+ if (p.action) url.searchParams.set("action", p.action);
23
+ if (p.actor) url.searchParams.set("actor", p.actor);
24
+ if (p.actorType) url.searchParams.set("actor_type", p.actorType);
25
+ if (p.tenantId) url.searchParams.set("tenant_id", p.tenantId);
26
+ if (p.targetType) url.searchParams.set("target_type", p.targetType);
27
+ if (p.targetId) url.searchParams.set("target_id", p.targetId);
28
+ if (p.resultStatus) url.searchParams.set("result_status", p.resultStatus);
29
+ if (p.originIP) url.searchParams.set("origin_ip", p.originIP);
30
+ if (p.q) url.searchParams.set("q", p.q);
31
+ }
32
+ async function getEvent(opts) {
33
+ const url = new URL(joinUrl(opts.apiBase, `events/${encodeURIComponent(opts.id)}`));
34
+ return request(url, opts);
35
+ }
36
+ async function listDistinctActions(opts) {
37
+ const url = new URL(joinUrl(opts.apiBase, "events/actions"));
38
+ return request(url, opts);
39
+ }
40
+ async function listDistinctActorTypes(opts) {
41
+ const url = new URL(joinUrl(opts.apiBase, "events/actor-types"));
42
+ return request(url, opts);
43
+ }
44
+ async function listDistinctTargetTypes(opts) {
45
+ const url = new URL(joinUrl(opts.apiBase, "events/target-types"));
46
+ return request(url, opts);
47
+ }
48
+ async function listDistinctTenants(opts) {
49
+ const url = new URL(joinUrl(opts.apiBase, "events/tenants"));
50
+ return request(url, opts);
51
+ }
52
+ async function listDistinctResultStatuses(opts) {
53
+ const url = new URL(joinUrl(opts.apiBase, "events/result-statuses"));
54
+ return request(url, opts);
55
+ }
56
+ async function listMetadataKeys(opts) {
57
+ const url = new URL(joinUrl(opts.apiBase, "events/metadata-keys"));
58
+ return request(url, opts);
59
+ }
60
+ async function listChangeFields(opts) {
61
+ const url = new URL(joinUrl(opts.apiBase, "events/change-fields"));
62
+ return request(url, opts);
63
+ }
64
+ async function generateNLPFilters(opts) {
65
+ const url = new URL(joinUrl(opts.apiBase, "events/nlp"));
66
+ const body = { q: opts.query };
67
+ let res;
68
+ try {
69
+ res = await fetch(url, {
70
+ method: "POST",
71
+ headers: {
72
+ Authorization: `Bearer ${opts.token}`,
73
+ "Content-Type": "application/json"
74
+ },
75
+ body: JSON.stringify(body),
76
+ signal: opts.signal
77
+ });
78
+ } catch (err) {
79
+ if (err instanceof DOMException && err.name === "AbortError") throw err;
80
+ throw new EmbedError({ kind: "network", cause: err, message: "network error" });
81
+ }
82
+ if (res.ok) return await res.json();
83
+ if (res.status === 403) {
84
+ const message = (await res.text()).trim() || "nlp_not_allowed";
85
+ throw new EmbedError({ kind: "bad_request", status: 403, message });
86
+ }
87
+ throw await mapErrorResponse(res);
88
+ }
89
+ async function exportEvents(opts) {
90
+ const url = new URL(joinUrl(opts.apiBase, "events/export"));
91
+ const { format, ...rest } = opts.params;
92
+ url.searchParams.set("format", format);
93
+ applyListParams(url, rest);
94
+ let res;
95
+ try {
96
+ res = await fetch(url, {
97
+ headers: { Authorization: `Bearer ${opts.token}` },
98
+ signal: opts.signal
99
+ });
100
+ } catch (err) {
101
+ if (err instanceof DOMException && err.name === "AbortError") throw err;
102
+ throw new EmbedError({ kind: "network", cause: err, message: "network error" });
103
+ }
104
+ if (!res.ok) throw await mapErrorResponse(res);
105
+ const blob = await res.blob();
106
+ const filename = parseFilenameFromContentDisposition(res.headers.get("Content-Disposition")) ?? `events.${format}`;
107
+ return { blob, filename };
108
+ }
109
+ function parseFilenameFromContentDisposition(value) {
110
+ if (!value) return void 0;
111
+ const quoted = /filename="([^"]+)"/.exec(value);
112
+ if (quoted?.[1]) return quoted[1];
113
+ const unquoted = /filename=([^;]+)/.exec(value);
114
+ if (unquoted?.[1]) return unquoted[1].trim();
115
+ return void 0;
116
+ }
117
+ async function request(url, opts) {
118
+ let res;
119
+ try {
120
+ res = await fetch(url, {
121
+ headers: { Authorization: `Bearer ${opts.token}` },
122
+ signal: opts.signal
123
+ });
124
+ } catch (err) {
125
+ if (err instanceof DOMException && err.name === "AbortError") throw err;
126
+ throw new EmbedError({ kind: "network", cause: err, message: "network error" });
127
+ }
128
+ if (res.ok) return await res.json();
129
+ throw await mapErrorResponse(res);
130
+ }
131
+ async function mapErrorResponse(res) {
132
+ switch (res.status) {
133
+ case 401:
134
+ return new EmbedError({ kind: "unauthorized", status: 401 });
135
+ case 404:
136
+ return new EmbedError({ kind: "not_found", status: 404 });
137
+ case 429: {
138
+ const retryAfterMs = parseRetryAfter(res.headers.get("Retry-After"));
139
+ return new EmbedError({ kind: "rate_limited", status: 429, retryAfterMs });
140
+ }
141
+ case 400: {
142
+ const message = (await res.text()).trim() || "bad request";
143
+ return new EmbedError({ kind: "bad_request", status: 400, message });
144
+ }
145
+ default:
146
+ return new EmbedError({
147
+ kind: "server",
148
+ status: res.status,
149
+ message: `unexpected status ${res.status}`
150
+ });
151
+ }
152
+ }
153
+ function parseRetryAfter(value) {
154
+ if (!value) return void 0;
155
+ const seconds = Number(value);
156
+ if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
157
+ const t = Date.parse(value);
158
+ if (!Number.isNaN(t)) return Math.max(0, t - Date.now());
159
+ return void 0;
160
+ }
161
+ function joinUrl(base, path) {
162
+ return `${base.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
163
+ }
164
+ async function fetchTokenViaOpts(opts) {
165
+ try {
166
+ if (opts.onTokenExpired) return await opts.onTokenExpired();
167
+ if (opts.tokenEndpoint) {
168
+ const res = await fetch(opts.tokenEndpoint, {
169
+ method: "POST",
170
+ credentials: "include"
171
+ });
172
+ if (!res.ok) return null;
173
+ const body = await res.json();
174
+ return body.token ?? null;
175
+ }
176
+ return null;
177
+ } catch {
178
+ return null;
179
+ }
180
+ }
181
+
182
+ // src/jwt.ts
183
+ function decodeJwtPayload(token) {
184
+ const parts = token.trim().split(".");
185
+ if (parts.length !== 3) {
186
+ throw new Error("malformed token: expected three dot-separated segments");
187
+ }
188
+ const b64url = parts[1];
189
+ if (!b64url) throw new Error("malformed token: empty payload segment");
190
+ const b64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
191
+ const pad = (4 - b64.length % 4) % 4;
192
+ const padded = b64 + "=".repeat(pad);
193
+ const binary = atob(padded);
194
+ const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
195
+ const json = new TextDecoder().decode(bytes);
196
+ return JSON.parse(json);
197
+ }
198
+
199
+ // src/claims.ts
200
+ function parseClaims(token) {
201
+ if (!token) return null;
202
+ try {
203
+ return decodeJwtPayload(token);
204
+ } catch {
205
+ return null;
206
+ }
207
+ }
208
+
209
+ // src/diff.ts
210
+ function renderDiff(change) {
211
+ if (change == null || typeof change !== "object") return { lines: [] };
212
+ const c = change;
213
+ if (c.before === void 0 && c.after === void 0) return { lines: [] };
214
+ const beforeStr = prettyJSON(c.before);
215
+ const afterStr = prettyJSON(c.after);
216
+ return { lines: lineDiff(splitLines(beforeStr), splitLines(afterStr)) };
217
+ }
218
+ function hasParseableDiff(change) {
219
+ if (change == null || typeof change !== "object") return false;
220
+ const c = change;
221
+ return c.before !== void 0 || c.after !== void 0;
222
+ }
223
+ function prettyJSON(v) {
224
+ if (v === void 0 || v === null) return "null";
225
+ try {
226
+ return JSON.stringify(v, null, 2);
227
+ } catch {
228
+ return String(v);
229
+ }
230
+ }
231
+ function splitLines(s) {
232
+ if (s === "") return [];
233
+ return s.split("\n");
234
+ }
235
+ function lineDiff(before, after) {
236
+ const n = before.length;
237
+ const m = after.length;
238
+ if (n === 0 && m === 0) return [];
239
+ const dp = Array.from(
240
+ { length: n + 1 },
241
+ () => new Array(m + 1).fill(0)
242
+ );
243
+ for (let i2 = n - 1; i2 >= 0; i2--) {
244
+ const row = dp[i2];
245
+ const next = dp[i2 + 1];
246
+ for (let j2 = m - 1; j2 >= 0; j2--) {
247
+ if (before[i2] === after[j2]) {
248
+ row[j2] = next[j2 + 1] + 1;
249
+ } else if (next[j2] >= row[j2 + 1]) {
250
+ row[j2] = next[j2];
251
+ } else {
252
+ row[j2] = row[j2 + 1];
253
+ }
254
+ }
255
+ }
256
+ const out = [];
257
+ let i = 0;
258
+ let j = 0;
259
+ while (i < n && j < m) {
260
+ if (before[i] === after[j]) {
261
+ out.push({
262
+ before: before[i],
263
+ after: after[j],
264
+ beforeKind: "same",
265
+ afterKind: "same"
266
+ });
267
+ i++;
268
+ j++;
269
+ } else if (dp[i + 1][j] >= dp[i][j + 1]) {
270
+ out.push({ before: before[i], after: "", beforeKind: "removed", afterKind: "" });
271
+ i++;
272
+ } else {
273
+ out.push({ before: "", after: after[j], beforeKind: "", afterKind: "added" });
274
+ j++;
275
+ }
276
+ }
277
+ while (i < n) {
278
+ out.push({ before: before[i], after: "", beforeKind: "removed", afterKind: "" });
279
+ i++;
280
+ }
281
+ while (j < m) {
282
+ out.push({ before: "", after: after[j], beforeKind: "", afterKind: "added" });
283
+ j++;
284
+ }
285
+ return out;
286
+ }
287
+
288
+ // src/columns.ts
289
+ var COLUMN_LABELS = {
290
+ id: "ID",
291
+ tenant_id: "Tenant",
292
+ occurred_at: "Time",
293
+ actor: "Actor",
294
+ action: "Action",
295
+ target: "Target",
296
+ metadata: "Metadata",
297
+ origin: "Origin",
298
+ result: "Result",
299
+ change: "Change",
300
+ idempotency_key: "Idempotency key"
301
+ };
302
+ var ALL_COLUMNS = [
303
+ "occurred_at",
304
+ "action",
305
+ "actor",
306
+ "target",
307
+ "tenant_id",
308
+ "result"
309
+ ];
310
+
311
+ // src/time.ts
312
+ var TIMESTAMP_FMT = new Intl.DateTimeFormat(void 0, {
313
+ year: "numeric",
314
+ month: "short",
315
+ day: "numeric",
316
+ hour: "numeric",
317
+ minute: "2-digit",
318
+ second: "2-digit"
319
+ });
320
+ function formatAbsolute(rfc3339) {
321
+ const d = new Date(rfc3339);
322
+ if (Number.isNaN(d.getTime())) return rfc3339;
323
+ return TIMESTAMP_FMT.format(d);
324
+ }
325
+ function formatRelative(rfc3339, now) {
326
+ const d = new Date(rfc3339);
327
+ if (Number.isNaN(d.getTime())) return "";
328
+ const ms = now - d.getTime();
329
+ if (ms < 0) return "just now";
330
+ const seconds = Math.floor(ms / 1e3);
331
+ if (seconds < 30) return "just now";
332
+ if (seconds < 60) return `${seconds}s ago`;
333
+ const minutes = Math.floor(seconds / 60);
334
+ if (minutes < 60) return `${minutes}m ago`;
335
+ const hours = Math.floor(minutes / 60);
336
+ if (hours < 24) return `${hours}h ago`;
337
+ const days = Math.floor(hours / 24);
338
+ if (days < 30) return `${days}d ago`;
339
+ const months = Math.floor(days / 30);
340
+ if (months < 12) return `${months}mo ago`;
341
+ const years = Math.floor(days / 365);
342
+ return `${years}y ago`;
343
+ }
344
+ function formatTimeCell(rfc3339, now) {
345
+ const absolute = formatAbsolute(rfc3339);
346
+ const relative = formatRelative(rfc3339, now);
347
+ if (!relative) return absolute;
348
+ return `${absolute} (${relative})`;
349
+ }
350
+ var RELATIVE_TIME_TICK_MS = 3e4;
351
+
352
+ // src/eventsStore.ts
353
+ var MIN_POLL_INTERVAL_MS = 1e3;
354
+ var INITIAL_STATE = {
355
+ events: [],
356
+ nextCursor: null,
357
+ status: "loading",
358
+ error: null
359
+ };
360
+ function createEventsStore(config) {
361
+ let state = INITIAL_STATE;
362
+ const listeners = /* @__PURE__ */ new Set();
363
+ let token = config.token;
364
+ let disposed = false;
365
+ let activeAbort = null;
366
+ let pollTimer = null;
367
+ let visibilityHandler = null;
368
+ const setState = (next) => {
369
+ state = next;
370
+ for (const l of listeners) l();
371
+ };
372
+ const fetchPage = async (kind, signal) => {
373
+ if (!token) return;
374
+ const params = { limit: config.pageSize };
375
+ if (config.since) params.since = config.since;
376
+ if (config.before) params.before = config.before;
377
+ if (config.action) params.action = config.action;
378
+ if (config.actor) params.actor = config.actor;
379
+ if (config.actorType) params.actorType = config.actorType;
380
+ if (config.tenantId) params.tenantId = config.tenantId;
381
+ if (config.targetType) params.targetType = config.targetType;
382
+ if (config.targetId) params.targetId = config.targetId;
383
+ if (config.resultStatus) params.resultStatus = config.resultStatus;
384
+ if (config.originIP) params.originIP = config.originIP;
385
+ if (config.q) params.q = config.q;
386
+ if (kind === "poll") {
387
+ const newest = state.events[0]?.occurred_at;
388
+ if (newest) params.since = newest;
389
+ } else if (kind === "more") {
390
+ if (!state.nextCursor) return;
391
+ params.cursor = state.nextCursor;
392
+ }
393
+ const doFetch = async (t, allowRefresh) => {
394
+ try {
395
+ return await listEvents({ apiBase: config.apiBase, token: t, signal, params });
396
+ } catch (err) {
397
+ if (err instanceof DOMException && err.name === "AbortError") throw err;
398
+ if (allowRefresh && err instanceof EmbedError && err.kind === "unauthorized") {
399
+ const newTok = await fetchTokenViaOpts({
400
+ tokenEndpoint: config.tokenEndpoint,
401
+ onTokenExpired: config.onTokenExpired
402
+ });
403
+ if (!newTok) throw err;
404
+ token = newTok;
405
+ return doFetch(newTok, false);
406
+ }
407
+ throw err;
408
+ }
409
+ };
410
+ let response;
411
+ try {
412
+ response = await doFetch(token, true);
413
+ } catch (err) {
414
+ if (err instanceof DOMException && err.name === "AbortError") return;
415
+ const e = err instanceof EmbedError ? err : new EmbedError({ kind: "network", cause: err, message: "network error" });
416
+ setState({
417
+ ...state,
418
+ status: e.kind === "unauthorized" ? "expired" : "error",
419
+ error: e
420
+ });
421
+ config.onError?.(e);
422
+ return;
423
+ }
424
+ if (kind === "initial") {
425
+ setState({
426
+ events: response.events,
427
+ nextCursor: response.next_cursor ?? null,
428
+ status: "ok",
429
+ error: null
430
+ });
431
+ } else if (kind === "poll") {
432
+ const events = response.events.length > 0 ? mergeNewer(response.events, state.events) : state.events;
433
+ setState({ ...state, events, status: "ok", error: null });
434
+ } else {
435
+ setState({
436
+ events: mergeOlder(state.events, response.events),
437
+ nextCursor: response.next_cursor ?? null,
438
+ status: "ok",
439
+ error: null
440
+ });
441
+ }
442
+ };
443
+ const startPolling = () => {
444
+ if (config.pollInterval <= 0) return;
445
+ if (config.before) return;
446
+ let interval = config.pollInterval;
447
+ if (interval < MIN_POLL_INTERVAL_MS) {
448
+ console.warn(
449
+ `[everscribe] pollInterval=${interval}ms is below minimum ${MIN_POLL_INTERVAL_MS}ms; clamping to ${MIN_POLL_INTERVAL_MS}ms`
450
+ );
451
+ interval = MIN_POLL_INTERVAL_MS;
452
+ }
453
+ const schedule = () => {
454
+ if (disposed) return;
455
+ pollTimer = setTimeout(tick, interval);
456
+ };
457
+ const tick = async () => {
458
+ if (disposed) return;
459
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
460
+ schedule();
461
+ return;
462
+ }
463
+ const ctrl = new AbortController();
464
+ activeAbort = ctrl;
465
+ try {
466
+ await fetchPage("poll", ctrl.signal);
467
+ } finally {
468
+ if (activeAbort === ctrl) activeAbort = null;
469
+ schedule();
470
+ }
471
+ };
472
+ schedule();
473
+ if (typeof document !== "undefined") {
474
+ visibilityHandler = () => {
475
+ if (disposed) return;
476
+ if (document.visibilityState === "visible") {
477
+ if (pollTimer) {
478
+ clearTimeout(pollTimer);
479
+ pollTimer = null;
480
+ }
481
+ void tick();
482
+ }
483
+ };
484
+ document.addEventListener("visibilitychange", visibilityHandler);
485
+ }
486
+ };
487
+ const stopPolling = () => {
488
+ if (pollTimer) {
489
+ clearTimeout(pollTimer);
490
+ pollTimer = null;
491
+ }
492
+ if (visibilityHandler && typeof document !== "undefined") {
493
+ document.removeEventListener("visibilitychange", visibilityHandler);
494
+ visibilityHandler = null;
495
+ }
496
+ };
497
+ const runInitialFetch = () => {
498
+ if (!token) return;
499
+ const ctrl = new AbortController();
500
+ activeAbort = ctrl;
501
+ void fetchPage("initial", ctrl.signal).finally(() => {
502
+ if (activeAbort === ctrl) activeAbort = null;
503
+ });
504
+ };
505
+ runInitialFetch();
506
+ startPolling();
507
+ return {
508
+ getSnapshot: () => state,
509
+ subscribe(listener) {
510
+ listeners.add(listener);
511
+ return () => {
512
+ listeners.delete(listener);
513
+ };
514
+ },
515
+ loadMore() {
516
+ if (disposed) return;
517
+ if (!state.nextCursor) return;
518
+ const ctrl = new AbortController();
519
+ void fetchPage("more", ctrl.signal);
520
+ },
521
+ refresh() {
522
+ if (disposed) return;
523
+ stopPolling();
524
+ if (activeAbort) activeAbort.abort();
525
+ setState(INITIAL_STATE);
526
+ runInitialFetch();
527
+ startPolling();
528
+ },
529
+ dispose() {
530
+ if (disposed) return;
531
+ disposed = true;
532
+ stopPolling();
533
+ if (activeAbort) activeAbort.abort();
534
+ listeners.clear();
535
+ }
536
+ };
537
+ }
538
+ function mergeNewer(incoming, existing) {
539
+ const seen = new Set(existing.map((e) => e.id));
540
+ const fresh = incoming.filter((e) => !seen.has(e.id));
541
+ if (fresh.length === 0) return existing;
542
+ return [...fresh, ...existing];
543
+ }
544
+ function mergeOlder(existing, incoming) {
545
+ const seen = new Set(existing.map((e) => e.id));
546
+ const fresh = incoming.filter((e) => !seen.has(e.id));
547
+ return [...existing, ...fresh];
548
+ }
549
+
550
+ // src/distinctValuesStore.ts
551
+ var EMPTY_DISTINCT_VALUES = {
552
+ actions: [],
553
+ actorTypes: [],
554
+ targetTypes: [],
555
+ tenants: [],
556
+ resultStatuses: [],
557
+ metadataKeys: [],
558
+ changeFields: []
559
+ };
560
+ function createDistinctValuesStore(config) {
561
+ let state = EMPTY_DISTINCT_VALUES;
562
+ const listeners = /* @__PURE__ */ new Set();
563
+ const ctrl = new AbortController();
564
+ let disposed = false;
565
+ const setState = (next) => {
566
+ state = next;
567
+ for (const l of listeners) l();
568
+ };
569
+ const fetchOnce = async (token) => {
570
+ const base = { apiBase: config.apiBase, token, signal: ctrl.signal };
571
+ const [actions, actorTypes, targetTypes, tenants, statuses, mdk, cf] = await Promise.all([
572
+ listDistinctActions(base).catch(() => ({ actions: [] })),
573
+ listDistinctActorTypes(base).catch(() => ({ actor_types: [] })),
574
+ listDistinctTargetTypes(base).catch(() => ({ target_types: [] })),
575
+ // The server returns an empty list when the token is tenant-
576
+ // scoped, so the UI hides the tenant dropdown for those tokens
577
+ // automatically.
578
+ listDistinctTenants(base).catch(() => ({ tenants: [] })),
579
+ listDistinctResultStatuses(base).catch(() => ({ statuses: [] })),
580
+ listMetadataKeys(base).catch(() => ({ keys: [] })),
581
+ listChangeFields(base).catch(() => ({ fields: [] }))
582
+ ]);
583
+ if (disposed) return;
584
+ setState({
585
+ actions: actions.actions ?? [],
586
+ actorTypes: actorTypes.actor_types ?? [],
587
+ targetTypes: targetTypes.target_types ?? [],
588
+ tenants: tenants.tenants ?? [],
589
+ resultStatuses: statuses.statuses ?? [],
590
+ metadataKeys: mdk.keys ?? [],
591
+ changeFields: cf.fields ?? []
592
+ });
593
+ };
594
+ if (config.token) {
595
+ void (async () => {
596
+ try {
597
+ await fetchOnce(config.token);
598
+ } catch (err) {
599
+ if (err instanceof DOMException && err.name === "AbortError") return;
600
+ if (err instanceof EmbedError && err.kind === "unauthorized") {
601
+ const refreshed = await fetchTokenViaOpts({
602
+ tokenEndpoint: config.tokenEndpoint,
603
+ onTokenExpired: config.onTokenExpired
604
+ });
605
+ if (refreshed && !disposed) {
606
+ try {
607
+ await fetchOnce(refreshed);
608
+ } catch {
609
+ }
610
+ }
611
+ }
612
+ }
613
+ })();
614
+ }
615
+ return {
616
+ getSnapshot: () => state,
617
+ subscribe(listener) {
618
+ listeners.add(listener);
619
+ return () => {
620
+ listeners.delete(listener);
621
+ };
622
+ },
623
+ dispose() {
624
+ if (disposed) return;
625
+ disposed = true;
626
+ ctrl.abort();
627
+ listeners.clear();
628
+ }
629
+ };
630
+ }
631
+
632
+ export { ALL_COLUMNS, COLUMN_LABELS, EMPTY_DISTINCT_VALUES, EmbedError, RELATIVE_TIME_TICK_MS, createDistinctValuesStore, createEventsStore, decodeJwtPayload, exportEvents, fetchTokenViaOpts, formatAbsolute, formatRelative, formatTimeCell, generateNLPFilters, getEvent, hasParseableDiff, listChangeFields, listDistinctActions, listDistinctActorTypes, listDistinctResultStatuses, listDistinctTargetTypes, listDistinctTenants, listEvents, listMetadataKeys, parseClaims, renderDiff };
633
+ //# sourceMappingURL=index.js.map
634
+ //# sourceMappingURL=index.js.map