@powersync/nuxt 0.0.0-dev-20260128023420

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 (64) hide show
  1. package/LICENSE +201 -0
  2. package/README +374 -0
  3. package/dist/module.d.mts +39 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +160 -0
  6. package/dist/runtime/assets/powersync-icon.svg +14 -0
  7. package/dist/runtime/components/BucketsInspectorTab.d.vue.ts +3 -0
  8. package/dist/runtime/components/BucketsInspectorTab.vue +646 -0
  9. package/dist/runtime/components/BucketsInspectorTab.vue.d.ts +3 -0
  10. package/dist/runtime/components/ConfigInspectorTab.d.vue.ts +3 -0
  11. package/dist/runtime/components/ConfigInspectorTab.vue +121 -0
  12. package/dist/runtime/components/ConfigInspectorTab.vue.d.ts +3 -0
  13. package/dist/runtime/components/DataInspectorTab.d.vue.ts +3 -0
  14. package/dist/runtime/components/DataInspectorTab.vue +678 -0
  15. package/dist/runtime/components/DataInspectorTab.vue.d.ts +3 -0
  16. package/dist/runtime/components/LoadingSpinner.d.vue.ts +3 -0
  17. package/dist/runtime/components/LoadingSpinner.vue +12 -0
  18. package/dist/runtime/components/LoadingSpinner.vue.d.ts +3 -0
  19. package/dist/runtime/components/LogsTab.d.vue.ts +3 -0
  20. package/dist/runtime/components/LogsTab.vue +325 -0
  21. package/dist/runtime/components/LogsTab.vue.d.ts +3 -0
  22. package/dist/runtime/components/PowerSyncInstanceTab.d.vue.ts +3 -0
  23. package/dist/runtime/components/PowerSyncInstanceTab.vue +9 -0
  24. package/dist/runtime/components/PowerSyncInstanceTab.vue.d.ts +3 -0
  25. package/dist/runtime/components/SyncStatusTab.d.vue.ts +3 -0
  26. package/dist/runtime/components/SyncStatusTab.vue +272 -0
  27. package/dist/runtime/components/SyncStatusTab.vue.d.ts +3 -0
  28. package/dist/runtime/composables/useDiagnosticsLogger.d.ts +27 -0
  29. package/dist/runtime/composables/useDiagnosticsLogger.js +41 -0
  30. package/dist/runtime/composables/usePowerSyncInspector.d.ts +42 -0
  31. package/dist/runtime/composables/usePowerSyncInspector.js +19 -0
  32. package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.d.ts +153 -0
  33. package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.js +254 -0
  34. package/dist/runtime/composables/usePowerSyncKysely.d.ts +23 -0
  35. package/dist/runtime/composables/usePowerSyncKysely.js +7 -0
  36. package/dist/runtime/index.d.ts +9 -0
  37. package/dist/runtime/layouts/powersync-inspector-layout.d.vue.ts +13 -0
  38. package/dist/runtime/layouts/powersync-inspector-layout.vue +90 -0
  39. package/dist/runtime/layouts/powersync-inspector-layout.vue.d.ts +13 -0
  40. package/dist/runtime/pages/__powersync-inspector.d.vue.ts +3 -0
  41. package/dist/runtime/pages/__powersync-inspector.vue +153 -0
  42. package/dist/runtime/pages/__powersync-inspector.vue.d.ts +3 -0
  43. package/dist/runtime/plugin.client.d.ts +2 -0
  44. package/dist/runtime/plugin.client.js +11 -0
  45. package/dist/runtime/utils/AppSchema.d.ts +27 -0
  46. package/dist/runtime/utils/AppSchema.js +23 -0
  47. package/dist/runtime/utils/DynamicSchemaManager.d.ts +15 -0
  48. package/dist/runtime/utils/DynamicSchemaManager.js +91 -0
  49. package/dist/runtime/utils/JsSchemaGenerator.d.ts +8 -0
  50. package/dist/runtime/utils/JsSchemaGenerator.js +28 -0
  51. package/dist/runtime/utils/NuxtPowerSyncDatabase.d.ts +40 -0
  52. package/dist/runtime/utils/NuxtPowerSyncDatabase.js +117 -0
  53. package/dist/runtime/utils/RecordingStorageAdapter.d.ts +13 -0
  54. package/dist/runtime/utils/RecordingStorageAdapter.js +76 -0
  55. package/dist/runtime/utils/RustClientInterceptor.d.ts +24 -0
  56. package/dist/runtime/utils/RustClientInterceptor.js +102 -0
  57. package/dist/runtime/utils/TokenConnector.d.ts +14 -0
  58. package/dist/runtime/utils/TokenConnector.js +62 -0
  59. package/dist/runtime/utils/addImportsFrom.d.ts +1 -0
  60. package/dist/runtime/utils/addImportsFrom.js +4 -0
  61. package/dist/runtime/utils/index.d.ts +1 -0
  62. package/dist/runtime/utils/index.js +1 -0
  63. package/dist/types.d.mts +9 -0
  64. package/package.json +90 -0
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <div class="loading-overlay">
3
+ <div class="loading-content">
4
+ <div class="spinner-icon"></div>
5
+ <div class="loading-text">Loading...</div>
6
+ </div>
7
+ </div>
8
+ </template>
9
+
10
+ <style scoped>
11
+ .loading-overlay{align-items:center;background:#fff;display:flex;inset:0;justify-content:center;position:fixed;z-index:9999}@media (prefers-color-scheme:dark){.loading-overlay{background:#0a0a0a}.loading-text{color:hsla(0,0%,100%,.7)}}.loading-content{align-items:center;animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite;display:flex;flex-direction:column;font-size:18px;gap:12px}.loading-text{color:rgba(0,0,0,.7)}.spinner-icon{animation:spin 1s linear infinite;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik03LjcgNC43YTE0LjcgMTQuNyAwIDAgMC0zIDMuMUw2LjMgOWExMy4zIDEzLjMgMCAwIDEgMi42LTIuN1ptLTMuMSA3LjYtMS45LS42QTEyLjUgMTIuNSAwIDAgMCAyIDE2aDJhMTEuNSAxMS41IDAgMCAxIC42LTMuN20tMS45IDguMWExNC40IDE0LjQgMCAwIDAgMiAzLjlsMS42LTEuMmExMi45IDEyLjkgMCAwIDEtMS43LTMuM1ptNS4xIDYuOWExNC40IDE0LjQgMCAwIDAgMy45IDJsLjYtMS45QTEyLjkgMTIuOSAwIDAgMSA5IDI1LjdabTMuOS0yNC42LjYgMS45QTExLjUgMTEuNSAwIDAgMSAxNiA0VjJhMTIuNSAxMi41IDAgMCAwLTQuMy43bTEyLjUgMjQuNmExNS4yIDE1LjIgMCAwIDAgMy4xLTMuMUwyNS43IDIzYTExLjUgMTEuNSAwIDAgMS0yLjcgMi43Wm0zLjItNy42IDEuOS42QTE1LjUgMTUuNSAwIDAgMCAzMCAxNmgtMmExMS41IDExLjUgMCAwIDEtLjYgMy43bTEuOC04LjFhMTQuNCAxNC40IDAgMCAwLTItMy45bC0xLjYgMS4yYTEyLjkgMTIuOSAwIDAgMSAxLjcgMy4zWm0tNS4xLTdhMTQuNCAxNC40IDAgMCAwLTMuOS0ybC0uNiAxLjlhMTIuOSAxMi45IDAgMCAxIDMuMyAxLjdabS0zLjggMjQuNy0uNi0xLjlhMTEuNSAxMS41IDAgMCAxLTMuNy42djJhMjEuNCAyMS40IDAgMCAwIDQuMy0uNyIvPjwvc3ZnPg==");background-repeat:no-repeat;background-size:contain;height:36px;opacity:.5;width:36px}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes spin{to{transform:rotate(1turn)}}
12
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,325 @@
1
+ <template>
2
+ <div
3
+ border="t"
4
+ border-color="gray-100"
5
+ relative
6
+ n-bg="base"
7
+ flex="~ col"
8
+ h="screen"
9
+ overflow="hidden"
10
+ >
11
+ <!-- Toolbar -->
12
+ <div
13
+ class="flex items-center justify-between gap-3 px-3 py-2 border-b border-gray-200 dark:border-neutral-700"
14
+ >
15
+ <div class="flex items-center gap-2 flex-1">
16
+ <NTextInput
17
+ v-model="searchQuery"
18
+ n="xs"
19
+ class="flex-1 max-w-md"
20
+ placeholder="Search logs..."
21
+ icon="carbon:search"
22
+ />
23
+
24
+ <select
25
+ v-model="selectedLevel"
26
+ class="px-2 py-1 text-xs border border-gray-300 dark:border-neutral-600 rounded bg-white dark:bg-neutral-800"
27
+ >
28
+ <option value="all">
29
+ All Levels
30
+ </option>
31
+ <option value="error">
32
+ Error
33
+ </option>
34
+ <option value="warn">
35
+ Warning
36
+ </option>
37
+ <option value="info">
38
+ Info
39
+ </option>
40
+ <option value="debug">
41
+ Debug
42
+ </option>
43
+ </select>
44
+ </div>
45
+
46
+ <div class="flex items-center gap-2">
47
+ <NBadge n="slate xs">
48
+ {{ filteredLogs.length }}
49
+ </NBadge>
50
+ <NButton
51
+ n="xs red"
52
+ icon="carbon:trash-can"
53
+ @click="clearLogs"
54
+ >
55
+ Clear
56
+ </NButton>
57
+ </div>
58
+ </div>
59
+
60
+ <!-- Logs Table -->
61
+ <div class="flex-1 overflow-auto">
62
+ <div
63
+ v-if="filteredLogs.length === 0"
64
+ class="text-center py-12"
65
+ >
66
+ <div class="text-gray-500 dark:text-gray-400 text-sm">
67
+ No logs found
68
+ </div>
69
+ </div>
70
+
71
+ <table
72
+ v-else
73
+ class="w-full"
74
+ >
75
+ <thead class="sticky top-0 bg-gray-50 dark:bg-neutral-900 border-b border-gray-200 dark:border-neutral-700 z-10">
76
+ <tr>
77
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400 w-8" />
78
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400 w-32">
79
+ Time
80
+ </th>
81
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400 w-20">
82
+ Source
83
+ </th>
84
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400 w-20">
85
+ Level
86
+ </th>
87
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400">
88
+ Message
89
+ </th>
90
+ <th class="px-2 py-1.5 text-left text-xs font-medium text-gray-500 dark:text-gray-400 w-16" />
91
+ </tr>
92
+ </thead>
93
+ <tbody>
94
+ <template
95
+ v-for="log in filteredLogs"
96
+ :key="log.key"
97
+ >
98
+ <tr
99
+ class="log-entry hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors cursor-pointer border-b border-b-gray-100 dark:border-b-neutral-800"
100
+ @click="toggleExpand(log.key)"
101
+ >
102
+ <td class="px-2 py-1.5">
103
+ <div
104
+ class="w-1.5 h-1.5 rounded-full"
105
+ :class="getLogDotClass(log)"
106
+ />
107
+ </td>
108
+ <td class="px-2 py-1.5">
109
+ <span class="text-xs font-mono text-gray-600 dark:text-gray-400">
110
+ {{ log.value ? formatTime(log.value.date) : "" }}
111
+ </span>
112
+ </td>
113
+ <td class="px-2 py-1.5">
114
+ <div class="text-xs text-gray-700 dark:text-gray-300 truncate max-w-3xl">
115
+ {{ getLogSource(log) }}
116
+ </div>
117
+ </td>
118
+ <td class="px-2 py-1.5">
119
+ <NBadge
120
+ :n="`${getLogBadgeColor(log)} xs`"
121
+ >
122
+ {{ getLogType(log) }}
123
+ </NBadge>
124
+ </td>
125
+ <td class="px-2 py-1.5">
126
+ <div class="text-xs text-gray-700 dark:text-gray-300 truncate max-w-3xl">
127
+ {{ getLogMessage(log) }}
128
+ </div>
129
+ </td>
130
+ <td class="px-2 py-1.5 text-center">
131
+ <NIcon
132
+ v-if="hasExtraData(log)"
133
+ :icon="expandedLogs.has(log.key) ? 'carbon:chevron-up' : 'carbon:constraint'"
134
+ class="text-gray-600 text-xs"
135
+ />
136
+ </td>
137
+ </tr>
138
+ <tr
139
+ v-if="expandedLogs.has(log.key) && hasExtraData(log)"
140
+ class="bg-gray-50 dark:bg-neutral-900/50"
141
+ >
142
+ <td colspan="12">
143
+ <div class="px-10 py-2">
144
+ <div class="inline-flex items-center gap-2 mb-2">
145
+ <NIcon
146
+ n="sm"
147
+ icon="carbon:object"
148
+ />
149
+ <span class="text-xs text-gray-600 dark:text-gray-400">JSON</span>
150
+ </div>
151
+ <div class="bg-white dark:bg-neutral-800 p-3 rounded border border-gray-200 dark:border-neutral-700 overflow-x-auto">
152
+ <div
153
+ class="json-code-block text-xs"
154
+ v-html="highlightedJson.get(log.key)"
155
+ />
156
+ </div>
157
+ </div>
158
+ </td>
159
+ </tr>
160
+ </template>
161
+ </tbody>
162
+ </table>
163
+ </div>
164
+ </div>
165
+ </template>
166
+
167
+ <script setup>
168
+ import { useDiagnosticsLogger } from "#imports";
169
+ import { ref, computed, onMounted, onUnmounted } from "vue";
170
+ import Fuse from "fuse.js";
171
+ import { codeToHtml } from "shiki";
172
+ const { logsStorage, emitter } = useDiagnosticsLogger();
173
+ const searchQuery = ref("");
174
+ const selectedLevel = ref("all");
175
+ const expandedLogs = ref(/* @__PURE__ */ new Set());
176
+ const logs = ref([]);
177
+ const highlightedJson = ref(/* @__PURE__ */ new Map());
178
+ async function loadInitialLogs() {
179
+ const keys = await logsStorage.getKeys("log:");
180
+ const items = await logsStorage.getItems(keys.map((key) => ({ key })));
181
+ logs.value = items.sort((a, b) => {
182
+ const dateA = a.value ? new Date(a.value.date).getTime() : 0;
183
+ const dateB = b.value ? new Date(b.value.date).getTime() : 0;
184
+ return dateB - dateA;
185
+ });
186
+ }
187
+ const handleLog = (event) => {
188
+ logs.value.unshift({ key: event.key, value: event.value });
189
+ };
190
+ onMounted(() => {
191
+ loadInitialLogs();
192
+ emitter.on("log", handleLog);
193
+ });
194
+ onUnmounted(() => {
195
+ emitter.off("log", handleLog);
196
+ });
197
+ const fuse = computed(() => {
198
+ if (!logs.value || logs.value.length === 0) return null;
199
+ return new Fuse(logs.value, {
200
+ keys: [
201
+ { name: "message", getFn: (log) => getLogMessage(log), weight: 2 },
202
+ { name: "type", getFn: (log) => log.value?.type || "" },
203
+ { name: "extraData", getFn: (log) => getSearchableExtraData(log), weight: 0.5 }
204
+ ],
205
+ threshold: 0.3,
206
+ includeScore: true,
207
+ useExtendedSearch: true,
208
+ includeMatches: true
209
+ });
210
+ });
211
+ const filteredLogs = computed(() => {
212
+ let filtered = logs.value || [];
213
+ if (selectedLevel.value !== "all") {
214
+ filtered = filtered.filter(
215
+ (log) => log.value?.type === selectedLevel.value
216
+ );
217
+ }
218
+ if (searchQuery.value && fuse.value) {
219
+ const searchResults = fuse.value.search(searchQuery.value);
220
+ const searchedItems = searchResults.map((result) => result.item);
221
+ if (selectedLevel.value !== "all") {
222
+ filtered = filtered.filter(
223
+ (log) => searchedItems.some((item) => item.key === log.key)
224
+ );
225
+ } else {
226
+ filtered = searchedItems;
227
+ }
228
+ }
229
+ return filtered;
230
+ });
231
+ async function toggleExpand(key) {
232
+ if (expandedLogs.value.has(key)) {
233
+ expandedLogs.value.delete(key);
234
+ } else {
235
+ expandedLogs.value.add(key);
236
+ if (!highlightedJson.value.has(key)) {
237
+ const log = logs.value.find((l) => l.key === key);
238
+ if (log) {
239
+ const jsonStr = formatExtraData(log);
240
+ const html = await codeToHtml(jsonStr, {
241
+ lang: "json",
242
+ themes: {
243
+ light: "catppuccin-latte",
244
+ dark: "catppuccin-frappe"
245
+ }
246
+ });
247
+ highlightedJson.value.set(key, html);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ function getLogMessage(log) {
253
+ if (!log.value?.args || log.value.args.length === 0) return "Empty log message";
254
+ return String(log.value.args[0] || "Empty log message");
255
+ }
256
+ function getLogSource(log) {
257
+ return log.value?.args[2]?.name || "";
258
+ }
259
+ function hasExtraData(log) {
260
+ return !!(log.value?.args && log.value.args.length > 2 && log.value.args[1] && !(typeof log.value.args[1] === "object" && log.value.args[1] !== null && Object.keys(log.value.args[1]).length === 0));
261
+ }
262
+ function formatExtraData(log) {
263
+ if (!log.value?.args || log.value.args.length <= 1) return "";
264
+ return JSON.stringify(log.value.args[1], null, 2);
265
+ }
266
+ function getSearchableExtraData(log) {
267
+ if (!log.value?.args || log.value.args.length <= 1) return "";
268
+ const data = log.value.args[1];
269
+ if (!data) return "";
270
+ try {
271
+ const jsonStr = JSON.stringify(data);
272
+ const result = jsonStr.replace(/[{}[\]",:]/g, " ").replace(/\s+/g, " ").trim();
273
+ return result;
274
+ } catch {
275
+ return String(data);
276
+ }
277
+ }
278
+ function formatTime(date) {
279
+ return new Date(date).toLocaleTimeString("en-US", {
280
+ hour12: false,
281
+ hour: "2-digit",
282
+ minute: "2-digit",
283
+ second: "2-digit",
284
+ fractionalSecondDigits: 3
285
+ });
286
+ }
287
+ function getLogType(log) {
288
+ return (log.value?.type || "info").toUpperCase();
289
+ }
290
+ function getLogDotClass(log) {
291
+ const type = log.value?.type || "info";
292
+ const classes = {
293
+ error: "bg-red-500",
294
+ warn: "bg-yellow-500",
295
+ info: "bg-blue-500",
296
+ debug: "bg-gray-400"
297
+ };
298
+ return classes[type] || classes.info;
299
+ }
300
+ function getLogBadgeColor(log) {
301
+ const type = log.value?.type || "info";
302
+ const colors = {
303
+ error: "red",
304
+ warn: "yellow",
305
+ info: "blue",
306
+ debug: "gray"
307
+ };
308
+ return colors[type] || colors.info;
309
+ }
310
+ async function clearLogs() {
311
+ const keys = await logsStorage.getKeys("log:");
312
+ await Promise.all(keys.map((key) => logsStorage.removeItem(key)));
313
+ logs.value = [];
314
+ expandedLogs.value.clear();
315
+ highlightedJson.value.clear();
316
+ }
317
+ </script>
318
+
319
+ <style scoped>
320
+ .log-entry{animation:slideIn .2s ease-out}@keyframes slideIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
321
+ </style>
322
+
323
+ <style>
324
+ .json-code-block{font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:12px;line-height:1.4}.json-code-block pre{background:transparent!important;overflow:visible}.json-code-block code,.json-code-block pre{font-family:inherit;font-size:inherit;line-height:inherit;margin:0;padding:0}.json-code-block code{counter-increment:step 0;counter-reset:step;display:block}.json-code-block code .line:before{color:rgba(115,138,148,.4);content:counter(step);counter-increment:step;display:inline-block;margin-right:1.5rem;text-align:right;width:1rem}.dark .json-code-block code .line:before{color:#858080}
325
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <div>
3
+ <h1>PowerSync Instance</h1>
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+
9
+ </script>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,272 @@
1
+ <template>
2
+ <div
3
+ border="t"
4
+ border-color="gray-100"
5
+ relative
6
+ n-bg="base"
7
+ flex="~ col"
8
+ h="screen"
9
+ >
10
+ <div flex="~ col gap-2">
11
+ <NSectionBlock
12
+ icon="carbon:data-share"
13
+ text="Data Flow"
14
+ >
15
+ <div
16
+ grid="~ cols-6 gap-4"
17
+ mb="4"
18
+ >
19
+ <!-- Download Progress -->
20
+ <div flex="~ col gap-2">
21
+ <span text="sm gray-500">Download Progress</span>
22
+ <div flex="~ items-center gap-2">
23
+ <template v-if="downloadProgressDetails !== null">
24
+ <div
25
+ flex="1"
26
+ bg="gray-200"
27
+ rounded="full"
28
+ h="2"
29
+ >
30
+ <div
31
+ bg="blue-600"
32
+ h="2"
33
+ rounded="full"
34
+ transition="all"
35
+ duration="300"
36
+ :style="{
37
+ width: `${totalDownloadProgress}%`
38
+ }"
39
+ />
40
+ </div>
41
+ <span
42
+ text="sm"
43
+ font="medium"
44
+ >{{ totalDownloadProgress }}%</span>
45
+ </template>
46
+ <template v-else>
47
+ <span text="sm gray-400">No active download</span>
48
+ </template>
49
+ </div>
50
+ </div>
51
+
52
+ <!-- Error Indicator -->
53
+ <div flex="~ col gap-2">
54
+ <span text="sm gray-500">Status</span>
55
+ <NBadge
56
+ :n="downloadError ? 'red' : 'green'"
57
+ :icon="
58
+ downloadError ? 'carbon:warning-filled' : 'carbon:checkmark-filled'
59
+ "
60
+ >
61
+ {{ downloadError ? "Error" : "Healthy" }}
62
+ </NBadge>
63
+ </div>
64
+
65
+ <!-- Error Details -->
66
+ <div
67
+ flex="~ col gap-2"
68
+ col="span-4"
69
+ >
70
+ <span text="sm gray-500">Error Message</span>
71
+ <NBadge
72
+ v-if="downloadError"
73
+ n="red sm"
74
+ icon="carbon:warning-filled"
75
+ >
76
+ {{ downloadError.message }}
77
+ </NBadge>
78
+ <NBadge
79
+ v-else
80
+ n="slate sm"
81
+ icon="carbon:checkmark-filled"
82
+ >
83
+ N/A
84
+ </NBadge>
85
+ </div>
86
+ </div>
87
+
88
+ <div
89
+ grid="~ cols-6 gap-4"
90
+ mb="4"
91
+ >
92
+ <!-- Upload Progress -->
93
+ <div flex="~ col gap-2">
94
+ <span text="sm gray-500">Upload Progress</span>
95
+ <div flex="~ items-center gap-2">
96
+ <span v-if="syncStatus?.dataFlowStatus.uploading">upload in progress...</span>
97
+ <span
98
+ v-else
99
+ text="sm gray-400"
100
+ >No active upload</span>
101
+ </div>
102
+ </div>
103
+
104
+ <!-- Error Indicator -->
105
+ <div flex="~ col gap-2">
106
+ <span text="sm gray-500">Status</span>
107
+ <NBadge
108
+ :n="uploadError ? 'red' : 'green'"
109
+ :icon="
110
+ uploadError ? 'carbon:warning-filled' : 'carbon:checkmark-filled'
111
+ "
112
+ >
113
+ {{ uploadError ? "Error" : "Healthy" }}
114
+ </NBadge>
115
+ </div>
116
+
117
+ <div flex="~ col gap-2">
118
+ <span text="sm gray-500">Upload Queue Count</span>
119
+ <span text="sm"> {{ uploadQueueCount }} </span>
120
+ </div>
121
+
122
+ <div flex="~ col gap-2">
123
+ <span text="sm gray-500">Upload Queue Size</span>
124
+ <span text="sm">
125
+ {{ uploadQueueSize }}
126
+ </span>
127
+ </div>
128
+
129
+ <!-- Error Details -->
130
+ <div
131
+ flex="~ col gap-2"
132
+ col="span-2"
133
+ >
134
+ <span text="sm gray-500">Error Message</span>
135
+ <NBadge
136
+ v-if="uploadError"
137
+ n="red sm"
138
+ icon="carbon:warning-filled"
139
+ >
140
+ {{ uploadError.message }}
141
+ </NBadge>
142
+ <NBadge
143
+ v-else
144
+ n="slate sm"
145
+ icon="carbon:checkmark-filled"
146
+ >
147
+ N/A
148
+ </NBadge>
149
+ </div>
150
+ </div>
151
+ </NSectionBlock>
152
+
153
+ <span
154
+ border="b"
155
+ border-color="gray-100"
156
+ />
157
+
158
+ <NSectionBlock
159
+ icon="carbon:data-volume"
160
+ text="Data Size"
161
+ >
162
+ <NTip
163
+ v-if="!isDiagnosticSchemaSetup"
164
+ n="red6 dark:red5"
165
+ icon="carbon:warning-alt"
166
+ >
167
+ Make sure to extend your schema with the diagnostics schema using the
168
+ `diagnosticsSchema` from the `usePowerSyncInspector` composable.
169
+ </NTip>
170
+ <div
171
+ v-else
172
+ grid="~ cols-5 gap-4"
173
+ mb="4"
174
+ >
175
+ <div flex="~ col gap-2">
176
+ <span text="sm gray-500">Buckets Synced</span>
177
+ <span text="sm"> {{ totals?.buckets }} </span>
178
+ </div>
179
+
180
+ <div flex="~ col gap-2">
181
+ <span text="sm gray-500">Rows Synced</span>
182
+ <span text="sm"> {{ totals?.row_count }} </span>
183
+ </div>
184
+
185
+ <div flex="~ col gap-2">
186
+ <span text="sm gray-500">Data size</span>
187
+ <span text="sm">
188
+ {{ totals?.data_size }}
189
+ </span>
190
+ </div>
191
+
192
+ <div flex="~ col gap-2">
193
+ <span text="sm gray-500">Metadata size</span>
194
+ <span text="sm">
195
+ {{ totals?.metadata_size }}
196
+ </span>
197
+ </div>
198
+
199
+ <div flex="~ col gap-2">
200
+ <span text="sm gray-500">Download size</span>
201
+ <span text="sm">
202
+ {{ totals?.download_size }}
203
+ </span>
204
+ </div>
205
+ </div>
206
+ </NSectionBlock>
207
+
208
+ <span
209
+ border="b"
210
+ border-color="gray-100"
211
+ />
212
+
213
+ <NSectionBlock
214
+ icon="carbon:data-share"
215
+ text="Operations"
216
+ >
217
+ <NTip
218
+ v-if="!isDiagnosticSchemaSetup"
219
+ n="red6 dark:red5"
220
+ icon="carbon:warning-alt"
221
+ >
222
+ Make sure to extend your schema with the diagnostics schema using the
223
+ `diagnosticsSchema` from the `usePowerSyncInspector` composable.
224
+ </NTip>
225
+ <div
226
+ v-else
227
+ grid="~ cols-2 gap-4"
228
+ mb="4"
229
+ >
230
+ <div flex="~ col gap-2">
231
+ <span text="sm gray-500">Total operations</span>
232
+ <span text="sm">
233
+ {{ totals?.total_operations }}
234
+ </span>
235
+ </div>
236
+
237
+ <div flex="~ col gap-2">
238
+ <span text="sm gray-500">Downloaded operations</span>
239
+ <span text="sm">
240
+ {{ totals?.downloaded_operations }}
241
+ </span>
242
+ </div>
243
+ </div>
244
+ </NSectionBlock>
245
+
246
+ <span
247
+ border="b"
248
+ border-color="gray-100"
249
+ />
250
+ </div>
251
+ </div>
252
+ </template>
253
+
254
+ <script setup>
255
+ import { usePowerSyncInspectorDiagnostics } from "#imports";
256
+ import { onMounted } from "vue";
257
+ const {
258
+ db,
259
+ isDiagnosticSchemaSetup,
260
+ syncStatus,
261
+ downloadProgressDetails,
262
+ totalDownloadProgress,
263
+ downloadError,
264
+ uploadError,
265
+ uploadQueueCount,
266
+ uploadQueueSize,
267
+ totals
268
+ } = usePowerSyncInspectorDiagnostics();
269
+ onMounted(async () => {
270
+ await db.value?.waitForFirstSync();
271
+ });
272
+ </script>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,27 @@
1
+ import { type ILogHandler } from '@powersync/web';
2
+ /**
3
+ * Provides a logger configured for PowerSync diagnostics.
4
+ *
5
+ * This composable creates a logger instance that is automatically configured for diagnostics
6
+ * recording. The logger stores logs in session storage and emits events for real-time log monitoring.
7
+ *
8
+ * @param customHandler - Optional custom log handler to process log messages
9
+ *
10
+ * @returns An object containing:
11
+ * - `logger` - The configured ILogHandler instance
12
+ * - `logsStorage` - Storage instance for log persistence
13
+ * - `emitter` - Event emitter for log events
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const { logger } = useDiagnosticsLogger()
18
+ *
19
+ * // Logger is automatically configured for diagnostics
20
+ * // Use it in your PowerSync setup if needed
21
+ * ```
22
+ */
23
+ export declare const useDiagnosticsLogger: (customHandler?: ILogHandler) => {
24
+ logger: import("js-logger").GlobalLogger;
25
+ logsStorage: import("unstorage").Storage<import("unstorage").StorageValue>;
26
+ emitter: import("mitt").Emitter<Record<import("mitt").EventType, unknown>>;
27
+ };