@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.
- package/LICENSE +201 -0
- package/README +374 -0
- package/dist/module.d.mts +39 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +160 -0
- package/dist/runtime/assets/powersync-icon.svg +14 -0
- package/dist/runtime/components/BucketsInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/BucketsInspectorTab.vue +646 -0
- package/dist/runtime/components/BucketsInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/ConfigInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/ConfigInspectorTab.vue +121 -0
- package/dist/runtime/components/ConfigInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/DataInspectorTab.d.vue.ts +3 -0
- package/dist/runtime/components/DataInspectorTab.vue +678 -0
- package/dist/runtime/components/DataInspectorTab.vue.d.ts +3 -0
- package/dist/runtime/components/LoadingSpinner.d.vue.ts +3 -0
- package/dist/runtime/components/LoadingSpinner.vue +12 -0
- package/dist/runtime/components/LoadingSpinner.vue.d.ts +3 -0
- package/dist/runtime/components/LogsTab.d.vue.ts +3 -0
- package/dist/runtime/components/LogsTab.vue +325 -0
- package/dist/runtime/components/LogsTab.vue.d.ts +3 -0
- package/dist/runtime/components/PowerSyncInstanceTab.d.vue.ts +3 -0
- package/dist/runtime/components/PowerSyncInstanceTab.vue +9 -0
- package/dist/runtime/components/PowerSyncInstanceTab.vue.d.ts +3 -0
- package/dist/runtime/components/SyncStatusTab.d.vue.ts +3 -0
- package/dist/runtime/components/SyncStatusTab.vue +272 -0
- package/dist/runtime/components/SyncStatusTab.vue.d.ts +3 -0
- package/dist/runtime/composables/useDiagnosticsLogger.d.ts +27 -0
- package/dist/runtime/composables/useDiagnosticsLogger.js +41 -0
- package/dist/runtime/composables/usePowerSyncInspector.d.ts +42 -0
- package/dist/runtime/composables/usePowerSyncInspector.js +19 -0
- package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.d.ts +153 -0
- package/dist/runtime/composables/usePowerSyncInspectorDiagnostics.js +254 -0
- package/dist/runtime/composables/usePowerSyncKysely.d.ts +23 -0
- package/dist/runtime/composables/usePowerSyncKysely.js +7 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/layouts/powersync-inspector-layout.d.vue.ts +13 -0
- package/dist/runtime/layouts/powersync-inspector-layout.vue +90 -0
- package/dist/runtime/layouts/powersync-inspector-layout.vue.d.ts +13 -0
- package/dist/runtime/pages/__powersync-inspector.d.vue.ts +3 -0
- package/dist/runtime/pages/__powersync-inspector.vue +153 -0
- package/dist/runtime/pages/__powersync-inspector.vue.d.ts +3 -0
- package/dist/runtime/plugin.client.d.ts +2 -0
- package/dist/runtime/plugin.client.js +11 -0
- package/dist/runtime/utils/AppSchema.d.ts +27 -0
- package/dist/runtime/utils/AppSchema.js +23 -0
- package/dist/runtime/utils/DynamicSchemaManager.d.ts +15 -0
- package/dist/runtime/utils/DynamicSchemaManager.js +91 -0
- package/dist/runtime/utils/JsSchemaGenerator.d.ts +8 -0
- package/dist/runtime/utils/JsSchemaGenerator.js +28 -0
- package/dist/runtime/utils/NuxtPowerSyncDatabase.d.ts +40 -0
- package/dist/runtime/utils/NuxtPowerSyncDatabase.js +117 -0
- package/dist/runtime/utils/RecordingStorageAdapter.d.ts +13 -0
- package/dist/runtime/utils/RecordingStorageAdapter.js +76 -0
- package/dist/runtime/utils/RustClientInterceptor.d.ts +24 -0
- package/dist/runtime/utils/RustClientInterceptor.js +102 -0
- package/dist/runtime/utils/TokenConnector.d.ts +14 -0
- package/dist/runtime/utils/TokenConnector.js +62 -0
- package/dist/runtime/utils/addImportsFrom.d.ts +1 -0
- package/dist/runtime/utils/addImportsFrom.js +4 -0
- package/dist/runtime/utils/index.d.ts +1 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/types.d.mts +9 -0
- 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,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
|
+
};
|