@reddb-io/ui 0.1.1

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.
Files changed (169) hide show
  1. package/LICENSE +17 -0
  2. package/bin/red-ui.js +259 -0
  3. package/build/CNAME +1 -0
  4. package/build/_app/env.js +1 -0
  5. package/build/_app/immutable/assets/0.C63jY5jX.css +1 -0
  6. package/build/_app/immutable/assets/10.Dblyk0Kr.css +1 -0
  7. package/build/_app/immutable/assets/EmptyState.RXcH7ryE.css +1 -0
  8. package/build/_app/immutable/assets/Workspace.BCzG1DsH.css +1 -0
  9. package/build/_app/immutable/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2 +0 -0
  10. package/build/_app/immutable/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2 +0 -0
  11. package/build/_app/immutable/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2 +0 -0
  12. package/build/_app/immutable/assets/inter-greek-wght-normal.CkhJZR-_.woff2 +0 -0
  13. package/build/_app/immutable/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2 +0 -0
  14. package/build/_app/immutable/assets/inter-latin-wght-normal.Dx4kXJAl.woff2 +0 -0
  15. package/build/_app/immutable/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2 +0 -0
  16. package/build/_app/immutable/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
  17. package/build/_app/immutable/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
  18. package/build/_app/immutable/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
  19. package/build/_app/immutable/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
  20. package/build/_app/immutable/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
  21. package/build/_app/immutable/chunks/3j4cZ58b.js +1 -0
  22. package/build/_app/immutable/chunks/69_IOA4Y.js +1 -0
  23. package/build/_app/immutable/chunks/ALqaDrNQ.js +2 -0
  24. package/build/_app/immutable/chunks/BGcIe2ep.js +2 -0
  25. package/build/_app/immutable/chunks/BMHKbvs8.js +1 -0
  26. package/build/_app/immutable/chunks/BQHbwf54.js +916 -0
  27. package/build/_app/immutable/chunks/Bgso8cDH.js +311 -0
  28. package/build/_app/immutable/chunks/Bmgx1mfv.js +310 -0
  29. package/build/_app/immutable/chunks/BrvvOVaJ.js +1 -0
  30. package/build/_app/immutable/chunks/Bzak7iHL.js +1 -0
  31. package/build/_app/immutable/chunks/D9CTkMjK.js +1 -0
  32. package/build/_app/immutable/chunks/DIeogL5L.js +1 -0
  33. package/build/_app/immutable/chunks/DXY_Rxa7.js +113 -0
  34. package/build/_app/immutable/chunks/DhEqZVGG.js +1 -0
  35. package/build/_app/immutable/chunks/Ov8N-vxt.js +1 -0
  36. package/build/_app/immutable/chunks/oiO4RLqp.js +1 -0
  37. package/build/_app/immutable/entry/app.D_IVtpdv.js +2 -0
  38. package/build/_app/immutable/entry/start.3oC0UQ_Q.js +1 -0
  39. package/build/_app/immutable/nodes/0.CHPiFxDo.js +1 -0
  40. package/build/_app/immutable/nodes/1.BC_4YZ0h.js +1 -0
  41. package/build/_app/immutable/nodes/10.B7DMKSNc.js +60 -0
  42. package/build/_app/immutable/nodes/2.CAG5_cGP.js +1 -0
  43. package/build/_app/immutable/nodes/3.CAG5_cGP.js +1 -0
  44. package/build/_app/immutable/nodes/4.CAG5_cGP.js +1 -0
  45. package/build/_app/immutable/nodes/5.CAG5_cGP.js +1 -0
  46. package/build/_app/immutable/nodes/6.CAG5_cGP.js +1 -0
  47. package/build/_app/immutable/nodes/7.BZX9Iird.js +134 -0
  48. package/build/_app/immutable/nodes/8.CAG5_cGP.js +1 -0
  49. package/build/_app/immutable/nodes/9.CAG5_cGP.js +1 -0
  50. package/build/_app/version.json +1 -0
  51. package/build/favicon.png +0 -0
  52. package/build/index.html +59 -0
  53. package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js +26562 -0
  54. package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js.map +1 -0
  55. package/dist/embed/bundle-mjs-UuVRz3O4.js +3047 -0
  56. package/dist/embed/bundle-mjs-UuVRz3O4.js.map +1 -0
  57. package/dist/embed/core-QuRYvMt8.js +118 -0
  58. package/dist/embed/core-QuRYvMt8.js.map +1 -0
  59. package/dist/embed/index-B6ZQhCsu.js +577 -0
  60. package/dist/embed/index-B6ZQhCsu.js.map +1 -0
  61. package/dist/embed/index-client-ItCEU64C.js +3087 -0
  62. package/dist/embed/index-client-ItCEU64C.js.map +1 -0
  63. package/dist/embed/index-fad77a13.esm-BqPj0saH.js +1318 -0
  64. package/dist/embed/index-fad77a13.esm-BqPj0saH.js.map +1 -0
  65. package/dist/embed/index.js +11 -0
  66. package/dist/embed/index.js.map +1 -0
  67. package/dist/embed/sigma-node-border.esm-CGtlgqmo.js +432 -0
  68. package/dist/embed/sigma-node-border.esm-CGtlgqmo.js.map +1 -0
  69. package/dist/embed/sigma.esm-y0qgY-OC.js +2355 -0
  70. package/dist/embed/sigma.esm-y0qgY-OC.js.map +1 -0
  71. package/dist/embed/ui.css +1 -0
  72. package/package.json +101 -0
  73. package/src/app.css +238 -0
  74. package/src/lib/ActivityIndicator.svelte +100 -0
  75. package/src/lib/ClusterNode.svelte +119 -0
  76. package/src/lib/ClusterView.svelte +541 -0
  77. package/src/lib/CollectionHistory.svelte +266 -0
  78. package/src/lib/CollectionsView.svelte +14 -0
  79. package/src/lib/CommandPalette.svelte +237 -0
  80. package/src/lib/ConnectDropdown.svelte +222 -0
  81. package/src/lib/EmptyState.svelte +27 -0
  82. package/src/lib/LiveChanges.svelte +195 -0
  83. package/src/lib/MasterPasswordDialog.svelte +168 -0
  84. package/src/lib/PageHeader.svelte +32 -0
  85. package/src/lib/PendingChangesPanel.svelte +153 -0
  86. package/src/lib/QueryEditor.svelte +122 -0
  87. package/src/lib/ResultsPane.svelte +747 -0
  88. package/src/lib/SchemaTree.svelte +193 -0
  89. package/src/lib/SecurityView.svelte +255 -0
  90. package/src/lib/ShortcutOverlay.svelte +104 -0
  91. package/src/lib/Splash.svelte +46 -0
  92. package/src/lib/StatusBar.svelte +163 -0
  93. package/src/lib/SubNav.svelte +62 -0
  94. package/src/lib/Topbar.svelte +119 -0
  95. package/src/lib/Workspace.svelte +247 -0
  96. package/src/lib/activity.svelte.ts +91 -0
  97. package/src/lib/build-info.ts +41 -0
  98. package/src/lib/capability.ts +221 -0
  99. package/src/lib/cn.ts +6 -0
  100. package/src/lib/collection-catalog.ts +116 -0
  101. package/src/lib/collection-pages.ts +33 -0
  102. package/src/lib/connection-history.ts +301 -0
  103. package/src/lib/connections.svelte.ts +493 -0
  104. package/src/lib/embed/RedUiEmbedRoot.svelte +31 -0
  105. package/src/lib/embed/index.ts +234 -0
  106. package/src/lib/graph-loader/contract.ts +336 -0
  107. package/src/lib/graph-loader/drilldown.ts +334 -0
  108. package/src/lib/graph-loader/index.ts +13 -0
  109. package/src/lib/index.ts +114 -0
  110. package/src/lib/pending-changes.svelte.ts +149 -0
  111. package/src/lib/query-tabs.svelte.ts +130 -0
  112. package/src/lib/reddb/boot-params.ts +254 -0
  113. package/src/lib/reddb/cdc-stream-client.ts +234 -0
  114. package/src/lib/reddb/client.ts +698 -0
  115. package/src/lib/reddb/connection-bootstrap.ts +260 -0
  116. package/src/lib/reddb/connection-provider.contract.ts +72 -0
  117. package/src/lib/reddb/connection-provider.ts +72 -0
  118. package/src/lib/reddb/index.ts +14 -0
  119. package/src/lib/reddb/injected-client-provider.ts +76 -0
  120. package/src/lib/reddb/local-url-provider.ts +245 -0
  121. package/src/lib/reddb/secure-store.ts +41 -0
  122. package/src/lib/reddb/server-capabilities.ts +71 -0
  123. package/src/lib/reddb/tauri-encrypted-store.ts +64 -0
  124. package/src/lib/reddb/transports.ts +89 -0
  125. package/src/lib/reddb/types.ts +32 -0
  126. package/src/lib/reddb/uri.ts +54 -0
  127. package/src/lib/reddb/web-encrypted-store.ts +201 -0
  128. package/src/lib/renderers/DiffRenderer.svelte +184 -0
  129. package/src/lib/renderers/DocumentRenderer.svelte +134 -0
  130. package/src/lib/renderers/GraphRenderer.svelte +1328 -0
  131. package/src/lib/renderers/HypertableRenderer.svelte +253 -0
  132. package/src/lib/renderers/JsonRenderer.svelte +30 -0
  133. package/src/lib/renderers/KvRenderer.svelte +150 -0
  134. package/src/lib/renderers/QueueRenderer.svelte +286 -0
  135. package/src/lib/renderers/StatsRenderer.svelte +123 -0
  136. package/src/lib/renderers/TableRenderer.svelte +440 -0
  137. package/src/lib/renderers/VectorRenderer.svelte +388 -0
  138. package/src/lib/renderers/diff-render.ts +122 -0
  139. package/src/lib/renderers/diff.ts +9 -0
  140. package/src/lib/renderers/document-render.ts +64 -0
  141. package/src/lib/renderers/document.ts +9 -0
  142. package/src/lib/renderers/graph-render.ts +631 -0
  143. package/src/lib/renderers/graph-sigma.ts +395 -0
  144. package/src/lib/renderers/graph.ts +9 -0
  145. package/src/lib/renderers/hypertable-render.ts +320 -0
  146. package/src/lib/renderers/hypertable.ts +9 -0
  147. package/src/lib/renderers/index.ts +42 -0
  148. package/src/lib/renderers/json-render.ts +89 -0
  149. package/src/lib/renderers/json.ts +10 -0
  150. package/src/lib/renderers/kv-render.ts +193 -0
  151. package/src/lib/renderers/kv.ts +9 -0
  152. package/src/lib/renderers/queue-render.ts +197 -0
  153. package/src/lib/renderers/queue.ts +9 -0
  154. package/src/lib/renderers/registry.ts +68 -0
  155. package/src/lib/renderers/stats-render.ts +73 -0
  156. package/src/lib/renderers/stats.ts +9 -0
  157. package/src/lib/renderers/table-render.ts +156 -0
  158. package/src/lib/renderers/table.ts +11 -0
  159. package/src/lib/renderers/types.ts +33 -0
  160. package/src/lib/renderers/vector-render.ts +154 -0
  161. package/src/lib/renderers/vector.ts +9 -0
  162. package/src/lib/router.svelte.ts +163 -0
  163. package/src/lib/secureStore.svelte.ts +148 -0
  164. package/src/lib/shadow-dom-spike/ShadowDomSpikeCore.svelte +198 -0
  165. package/src/lib/shadow-dom-spike/mount-shadow-dom-spike.ts +94 -0
  166. package/src/lib/shortcuts.ts +22 -0
  167. package/src/lib/surface.ts +80 -0
  168. package/src/lib/tabs.svelte.ts +115 -0
  169. package/src/lib/theme.svelte.ts +63 -0
@@ -0,0 +1,301 @@
1
+ import type {
2
+ EncryptedStore,
3
+ HistoryEntry as ProtocolHistoryEntry,
4
+ HistoryStore,
5
+ } from "#reddb";
6
+ import type { Surface } from "./surface";
7
+
8
+ export type CredentialPersistence = "none" | "labels-only" | "vault";
9
+
10
+ export interface StoredLabelEntry {
11
+ id: string;
12
+ label: string;
13
+ last_used: number;
14
+ rtt_ms?: number;
15
+ }
16
+
17
+ export interface HistoryEntry {
18
+ id: string;
19
+ label: string;
20
+ last_used: number;
21
+ rtt_ms?: number;
22
+ /** Session/vault-hydrated URL. Absent on web after reload by design. */
23
+ url?: string;
24
+ }
25
+
26
+ export interface KeyValueStorage {
27
+ readonly length: number;
28
+ key(index: number): string | null;
29
+ getItem(key: string): string | null;
30
+ setItem(key: string, value: string): void;
31
+ removeItem(key: string): void;
32
+ }
33
+
34
+ export interface SurfaceHistoryStoreOptions {
35
+ surface: () => Surface;
36
+ secureStore: () => EncryptedStore | null;
37
+ managedWebTarget?: () => boolean;
38
+ storage?: KeyValueStorage;
39
+ historyKey?: string;
40
+ urlPrefix?: string;
41
+ }
42
+
43
+ export const DEFAULT_HISTORY_KEY = "red-ui:history";
44
+ export const DEFAULT_URL_PREFIX = "history:";
45
+
46
+ export function credentialPersistenceForSurface(
47
+ surface: Surface,
48
+ managedWebTarget = false
49
+ ): CredentialPersistence {
50
+ switch (surface) {
51
+ case "embedded":
52
+ return "none";
53
+ case "standalone":
54
+ return "vault";
55
+ case "web":
56
+ return managedWebTarget ? "none" : "labels-only";
57
+ }
58
+ }
59
+
60
+ export function safeConnectionLabel(entry: {
61
+ label?: string;
62
+ url?: string;
63
+ }): string {
64
+ if (entry.url) {
65
+ try {
66
+ const host = new URL(entry.url).host;
67
+ if (host) return host;
68
+ } catch {
69
+ // Fall through to the supplied label.
70
+ }
71
+ }
72
+
73
+ const raw = (entry.label ?? entry.url ?? "").trim();
74
+ if (!raw) return "";
75
+ try {
76
+ const host = new URL(raw).host;
77
+ if (host) return host;
78
+ } catch {
79
+ // A label is not necessarily a URL.
80
+ }
81
+ return raw.includes("@") ? raw.slice(raw.lastIndexOf("@") + 1) : raw;
82
+ }
83
+
84
+ function defaultStorage(): KeyValueStorage | undefined {
85
+ return typeof localStorage === "undefined" ? undefined : localStorage;
86
+ }
87
+
88
+ function labelHistoryId(label: string): string {
89
+ return `label:${encodeURIComponent(label)}`;
90
+ }
91
+
92
+ function genId(): string {
93
+ if (typeof crypto !== "undefined" && "randomUUID" in crypto)
94
+ return crypto.randomUUID();
95
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
96
+ }
97
+
98
+ function readLabels(
99
+ storage: KeyValueStorage | undefined,
100
+ historyKey: string
101
+ ): StoredLabelEntry[] {
102
+ if (!storage) return [];
103
+ try {
104
+ const raw = storage.getItem(historyKey);
105
+ if (!raw) return [];
106
+ const parsed = JSON.parse(raw) as Array<
107
+ StoredLabelEntry & { url?: string }
108
+ >;
109
+ if (!Array.isArray(parsed)) return [];
110
+ return parsed
111
+ .filter(
112
+ (e) => e && typeof e.id === "string" && typeof e.label === "string"
113
+ )
114
+ .map((e) => ({
115
+ id: e.id,
116
+ label: e.label,
117
+ last_used: e.last_used,
118
+ rtt_ms: e.rtt_ms,
119
+ }));
120
+ } catch {
121
+ return [];
122
+ }
123
+ }
124
+
125
+ function writeLabels(
126
+ storage: KeyValueStorage | undefined,
127
+ historyKey: string,
128
+ entries: StoredLabelEntry[]
129
+ ) {
130
+ if (!storage) return;
131
+ try {
132
+ storage.setItem(historyKey, JSON.stringify(entries));
133
+ } catch {
134
+ /* quota or disabled storage: history is best-effort */
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Surface-aware credential history.
140
+ *
141
+ * - web: labels go to localStorage; URL/credential strings stay in memory only.
142
+ * - standalone: labels go to localStorage; URLs go to the encrypted vault.
143
+ * - embedded/managed web: no history is read or written.
144
+ */
145
+ export class SurfaceHistoryStore implements HistoryStore {
146
+ private readonly surface: () => Surface;
147
+ private readonly secureStore: () => EncryptedStore | null;
148
+ private readonly managedWebTarget: () => boolean;
149
+ private readonly storage?: KeyValueStorage;
150
+ private readonly historyKey: string;
151
+ private readonly urlPrefix: string;
152
+ private idByUrl = new Map<string, string>();
153
+ private urlById = new Map<string, string>();
154
+ private onChange?: () => void;
155
+
156
+ constructor(opts: SurfaceHistoryStoreOptions) {
157
+ this.surface = opts.surface;
158
+ this.secureStore = opts.secureStore;
159
+ this.managedWebTarget = opts.managedWebTarget ?? (() => false);
160
+ this.storage = opts.storage ?? defaultStorage();
161
+ this.historyKey = opts.historyKey ?? DEFAULT_HISTORY_KEY;
162
+ this.urlPrefix = opts.urlPrefix ?? DEFAULT_URL_PREFIX;
163
+ }
164
+
165
+ setOnChange(fn: () => void) {
166
+ this.onChange = fn;
167
+ }
168
+
169
+ persistence(): CredentialPersistence {
170
+ return credentialPersistenceForSurface(
171
+ this.surface(),
172
+ this.managedWebTarget()
173
+ );
174
+ }
175
+
176
+ load(): ProtocolHistoryEntry[] {
177
+ if (this.persistence() === "none") return [];
178
+ return readLabels(this.storage, this.historyKey).map((l) => ({
179
+ url: this.urlById.get(l.id) ?? "",
180
+ label: l.label,
181
+ last_used: l.last_used,
182
+ rtt_ms: l.rtt_ms,
183
+ }));
184
+ }
185
+
186
+ save(entries: ProtocolHistoryEntry[]) {
187
+ const mode = this.persistence();
188
+ if (mode === "none") {
189
+ this.onChange?.();
190
+ return;
191
+ }
192
+
193
+ const previous = readLabels(this.storage, this.historyKey);
194
+ const previousByLabel = new Map(previous.map((l) => [l.label, l]));
195
+ const next: StoredLabelEntry[] = [];
196
+ const seen = new Set<string>();
197
+ const seenLabels = new Set<string>();
198
+
199
+ for (const e of entries) {
200
+ const label = safeConnectionLabel(e);
201
+ if (!label) continue;
202
+
203
+ let id: string | undefined;
204
+ if (e.url) {
205
+ id =
206
+ mode === "labels-only"
207
+ ? labelHistoryId(label)
208
+ : (this.idByUrl.get(e.url) ?? genId());
209
+ this.idByUrl.set(e.url, id);
210
+ this.urlById.set(id, e.url);
211
+ } else {
212
+ id = previousByLabel.get(label)?.id ?? labelHistoryId(label);
213
+ }
214
+ if (seen.has(id) || (!e.url && seenLabels.has(label))) continue;
215
+ seen.add(id);
216
+ seenLabels.add(label);
217
+
218
+ next.push({
219
+ id,
220
+ label,
221
+ last_used: typeof e.last_used === "number" ? e.last_used : Date.now(),
222
+ rtt_ms: e.rtt_ms,
223
+ });
224
+ }
225
+
226
+ writeLabels(this.storage, this.historyKey, next);
227
+
228
+ if (mode === "vault") {
229
+ const store = this.secureStore();
230
+ if (store) {
231
+ for (const row of next) {
232
+ const url = this.urlById.get(row.id);
233
+ if (url) store.put(this.urlPrefix + row.id, url).catch(() => {});
234
+ }
235
+ }
236
+ }
237
+
238
+ this.onChange?.();
239
+ }
240
+
241
+ uiEntries(): HistoryEntry[] {
242
+ if (this.persistence() === "none") return [];
243
+ return readLabels(this.storage, this.historyKey).map((l) => ({
244
+ id: l.id,
245
+ label: l.label,
246
+ last_used: l.last_used,
247
+ rtt_ms: l.rtt_ms,
248
+ url: this.urlById.get(l.id),
249
+ }));
250
+ }
251
+
252
+ async hydrate() {
253
+ if (this.persistence() !== "vault") return;
254
+ const store = this.secureStore();
255
+ if (!store) return;
256
+ const labels = readLabels(this.storage, this.historyKey);
257
+ let changed = false;
258
+ for (const l of labels) {
259
+ if (this.urlById.has(l.id)) continue;
260
+ try {
261
+ const url = await store.get(this.urlPrefix + l.id);
262
+ if (url) {
263
+ this.urlById.set(l.id, url);
264
+ this.idByUrl.set(url, l.id);
265
+ changed = true;
266
+ }
267
+ } catch {
268
+ /* tampered or wrong key: surface as missing URL */
269
+ }
270
+ }
271
+ if (changed) this.onChange?.();
272
+ }
273
+
274
+ async forgetById(id: string) {
275
+ if (this.persistence() === "none") {
276
+ this.onChange?.();
277
+ return;
278
+ }
279
+ const labels = readLabels(this.storage, this.historyKey).filter(
280
+ (l) => l.id !== id
281
+ );
282
+ writeLabels(this.storage, this.historyKey, labels);
283
+ const url = this.urlById.get(id);
284
+ if (url) {
285
+ this.urlById.delete(id);
286
+ this.idByUrl.delete(url);
287
+ }
288
+ const store = this.persistence() === "vault" ? this.secureStore() : null;
289
+ if (store) {
290
+ try {
291
+ await store.delete(this.urlPrefix + id);
292
+ } catch {}
293
+ }
294
+ this.onChange?.();
295
+ }
296
+
297
+ async forgetByUrl(url: string) {
298
+ const id = this.idByUrl.get(url);
299
+ if (id) await this.forgetById(id);
300
+ }
301
+ }