@myko/ui-vue 4.2.0-canary.10

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/.prettierrc ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "useTabs": true,
3
+ "singleQuote": true,
4
+ "trailingComma": "none",
5
+ "printWidth": 100
6
+ }
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @myko/ui-vue
2
+
3
+ Vue 3 reactive wrappers for the Myko client.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @myko/ui-vue
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Using Composables (Recommended)
14
+
15
+ ```vue
16
+ <script setup>
17
+ import { useQuery, useReport, useConnection } from '@myko/ui-vue'
18
+ import { queries, reports } from '@rship/entities'
19
+
20
+ // Connection management
21
+ const { status, isConnected, connect, disconnect } = useConnection()
22
+
23
+ // Query data with automatic cleanup
24
+ const { items, itemsArray, resolved } = useQuery(queries.GetAllTargets({}))
25
+
26
+ // Report data with automatic cleanup
27
+ const { value: count } = useReport(reports.CountAllTargets({}))
28
+
29
+ // Connect on mount
30
+ connect('ws://localhost:5155')
31
+ </script>
32
+
33
+ <template>
34
+ <div>Status: {{ status }}</div>
35
+ <div v-if="!resolved">Loading...</div>
36
+ <div v-for="target in itemsArray" :key="target.id">
37
+ {{ target.name }}
38
+ </div>
39
+ <div>Total: {{ count?.count ?? 0 }}</div>
40
+ </template>
41
+ ```
42
+
43
+ ### Using the Client Directly
44
+
45
+ ```vue
46
+ <script setup>
47
+ import { onUnmounted } from 'vue'
48
+ import { getMykoClient } from '@myko/ui-vue'
49
+ import { queries, commands } from '@rship/entities'
50
+
51
+ const client = getMykoClient()
52
+
53
+ // Manual query subscription
54
+ const { items, release } = client.query(queries.GetAllTargets({}))
55
+ onUnmounted(release)
56
+
57
+ // Send commands
58
+ async function deleteTarget(id: string) {
59
+ await client.sendCommand(commands.DeleteTarget({ targetId: id }))
60
+ }
61
+ </script>
62
+ ```
63
+
64
+ ## API
65
+
66
+ ### Composables
67
+
68
+ - `useQuery(queryFactory)` - Watch a query with reactive Map updates
69
+ - `useReport(reportFactory)` - Watch a report with reactive value
70
+ - `useConnection()` - Manage connection status
71
+
72
+ ### Client
73
+
74
+ - `getMykoClient()` - Get the global singleton client
75
+ - `createMykoClient()` - Create a new client instance
76
+ - `myko` - Direct access to the global client
77
+
78
+ ## Types
79
+
80
+ ```typescript
81
+ import type {
82
+ ReactiveQuery,
83
+ ReactiveReport,
84
+ UseQueryReturn,
85
+ UseReportReturn,
86
+ UseConnectionReturn
87
+ } from '@myko/ui-vue'
88
+ ```
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "dependencies": {
3
+ "@myko/core": "workspace:*"
4
+ },
5
+ "devDependencies": {
6
+ "@types/luxon": "^3.4.2",
7
+ "@vitejs/plugin-vue": "^5.0.0",
8
+ "luxon": "^3.5.0",
9
+ "prettier": "^3.3.2",
10
+ "rxjs": "^7.8.1",
11
+ "typescript": "^5.0.0",
12
+ "vite": "^5.0.11",
13
+ "vite-plugin-dts": "^3.7.0",
14
+ "vue": "^3.4.0",
15
+ "vue-tsc": "^2.0.0"
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "default": "./src/lib/index.ts"
20
+ }
21
+ },
22
+ "flux": {
23
+ "tasks": [
24
+ "build",
25
+ "check",
26
+ "publish"
27
+ ]
28
+ },
29
+ "main": "./src/lib/index.ts",
30
+ "name": "@myko/ui-vue",
31
+ "peerDependencies": {
32
+ "vue": "^3.4.0"
33
+ },
34
+ "repository": {
35
+ "directory": "libs/myko/ui-vue",
36
+ "type": "git",
37
+ "url": "https://github.com/ignition-is-go/myko"
38
+ },
39
+ "scripts": {
40
+ "build": "vue-tsc --noEmit",
41
+ "check": "vue-tsc --noEmit",
42
+ "dev": "vite build --watch",
43
+ "format": "prettier --write .",
44
+ "lint": "prettier --check ."
45
+ },
46
+ "type": "module",
47
+ "types": "./src/lib/index.ts",
48
+ "version": "4.2.0-canary.10"
49
+ }
@@ -0,0 +1,3 @@
1
+ export { useQuery, type UseQueryReturn } from './useQuery';
2
+ export { useReport, type UseReportReturn } from './useReport';
3
+ export { useConnection, type UseConnectionReturn } from './useConnection';
@@ -0,0 +1,57 @@
1
+ import { computed, type ComputedRef, type Ref } from 'vue';
2
+ import { ConnectionStatus } from '@myko/core';
3
+ import { getMykoClient } from '../services/vue-client';
4
+
5
+ export interface UseConnectionReturn {
6
+ /** Current connection status (reactive) */
7
+ status: Ref<ConnectionStatus>;
8
+ /** Whether currently connected (computed) */
9
+ isConnected: ComputedRef<boolean>;
10
+ /** Whether currently connecting (computed) */
11
+ isConnecting: ComputedRef<boolean>;
12
+ /** Whether currently disconnected (computed) */
13
+ isDisconnected: ComputedRef<boolean>;
14
+ /** Connect to a server address */
15
+ connect: (address: string) => void;
16
+ /** Disconnect from the server */
17
+ disconnect: () => void;
18
+ }
19
+
20
+ /**
21
+ * Vue composable for managing Myko connection status.
22
+ *
23
+ * @example
24
+ * ```vue
25
+ * <script setup>
26
+ * import { useConnection } from '@myko/ui-vue'
27
+ *
28
+ * const { status, isConnected, connect, disconnect } = useConnection()
29
+ *
30
+ * function handleConnect() {
31
+ * connect('ws://localhost:5155')
32
+ * }
33
+ * </script>
34
+ *
35
+ * <template>
36
+ * <div>Status: {{ status }}</div>
37
+ * <button v-if="!isConnected" @click="handleConnect">Connect</button>
38
+ * <button v-else @click="disconnect">Disconnect</button>
39
+ * </template>
40
+ * ```
41
+ */
42
+ export function useConnection(): UseConnectionReturn {
43
+ const client = getMykoClient();
44
+
45
+ const isConnected = computed(() => client.connectionStatus.value === ConnectionStatus.Connected);
46
+ const isConnecting = computed(() => client.connectionStatus.value === ConnectionStatus.Connecting);
47
+ const isDisconnected = computed(() => client.connectionStatus.value === ConnectionStatus.Disconnected);
48
+
49
+ return {
50
+ status: client.connectionStatus,
51
+ isConnected,
52
+ isConnecting,
53
+ isDisconnected,
54
+ connect: (address: string) => client.connect(address),
55
+ disconnect: () => client.disconnect()
56
+ };
57
+ }
@@ -0,0 +1,58 @@
1
+ import { onUnmounted, computed, type ComputedRef, type Ref } from 'vue';
2
+ import type { Query, QueryItem } from '@myko/core';
3
+ import { getMykoClient, type ReactiveQuery } from '../services/vue-client';
4
+
5
+ export interface UseQueryReturn<Q extends Query<unknown>> {
6
+ /** Reactive map of items by ID */
7
+ items: Map<string, QueryItem<Q> & { id: string }>;
8
+ /** Array of all items (computed for convenience) */
9
+ itemsArray: ComputedRef<(QueryItem<Q> & { id: string })[]>;
10
+ /** Whether the query has received its first response */
11
+ resolved: Ref<boolean>;
12
+ /** Manually release the subscription (also called on unmount) */
13
+ release: () => void;
14
+ }
15
+
16
+ /**
17
+ * Vue composable for watching a Myko query.
18
+ *
19
+ * Automatically releases the subscription when the component is unmounted.
20
+ *
21
+ * @example
22
+ * ```vue
23
+ * <script setup>
24
+ * import { useQuery } from '@myko/ui-vue'
25
+ * import { queries } from '@rship/entities'
26
+ *
27
+ * const { items, itemsArray, resolved } = useQuery(queries.GetAllTargets({}))
28
+ * </script>
29
+ *
30
+ * <template>
31
+ * <div v-if="!resolved">Loading...</div>
32
+ * <div v-for="target in itemsArray" :key="target.id">
33
+ * {{ target.name }}
34
+ * </div>
35
+ * </template>
36
+ * ```
37
+ */
38
+ export function useQuery<Q extends Query<unknown>>(
39
+ queryFactory: Q
40
+ ): UseQueryReturn<Q> {
41
+ const client = getMykoClient();
42
+ const result = client.query(queryFactory);
43
+
44
+ // Auto-release on unmount
45
+ onUnmounted(() => {
46
+ result.release();
47
+ });
48
+
49
+ // Convenience computed for array iteration
50
+ const itemsArray = computed(() => Array.from(result.items.values()));
51
+
52
+ return {
53
+ items: result.items,
54
+ itemsArray,
55
+ resolved: result.resolved,
56
+ release: result.release
57
+ };
58
+ }
@@ -0,0 +1,46 @@
1
+ import { onUnmounted, type ShallowRef } from 'vue';
2
+ import type { Report, ReportResult } from '@myko/core';
3
+ import { getMykoClient, type ReactiveReport } from '../services/vue-client';
4
+
5
+ export interface UseReportReturn<R extends Report<unknown>> {
6
+ /** Current value (reactive via ref) */
7
+ value: ShallowRef<ReportResult<R> | undefined>;
8
+ /** Manually release the subscription (also called on unmount) */
9
+ release: () => void;
10
+ }
11
+
12
+ /**
13
+ * Vue composable for watching a Myko report.
14
+ *
15
+ * Automatically releases the subscription when the component is unmounted.
16
+ *
17
+ * @example
18
+ * ```vue
19
+ * <script setup>
20
+ * import { useReport } from '@myko/ui-vue'
21
+ * import { reports } from '@rship/entities'
22
+ *
23
+ * const { value } = useReport(reports.CountAllTargets({}))
24
+ * </script>
25
+ *
26
+ * <template>
27
+ * <div>Count: {{ value?.count ?? 'loading...' }}</div>
28
+ * </template>
29
+ * ```
30
+ */
31
+ export function useReport<R extends Report<unknown>>(
32
+ reportFactory: R
33
+ ): UseReportReturn<R> {
34
+ const client = getMykoClient();
35
+ const result = client.report(reportFactory);
36
+
37
+ // Auto-release on unmount
38
+ onUnmounted(() => {
39
+ result.release();
40
+ });
41
+
42
+ return {
43
+ value: result.value,
44
+ release: result.release
45
+ };
46
+ }
@@ -0,0 +1,24 @@
1
+ // Vue-friendly Myko client exports
2
+ export {
3
+ createMykoClient,
4
+ getMykoClient,
5
+ myko,
6
+ VueMykoClient,
7
+ type CommandError,
8
+ type CommandSuccess,
9
+ type ReactiveQuery,
10
+ type ReactiveReport
11
+ } from './services/vue-client';
12
+
13
+ // Vue composables
14
+ export {
15
+ useQuery,
16
+ useReport,
17
+ useConnection,
18
+ type UseQueryReturn,
19
+ type UseReportReturn,
20
+ type UseConnectionReturn
21
+ } from './composables';
22
+
23
+ // Re-export useful types from @myko/ts
24
+ export { ConnectionStatus } from '@myko/core';
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Vue-friendly Myko client wrapper
3
+ *
4
+ * Provides reactive state using Vue 3 reactivity and reactive Map for efficient updates.
5
+ * Queries and reports are deduplicated - multiple calls with the same args share
6
+ * the same subscription and are only cancelled when all consumers unsubscribe.
7
+ */
8
+
9
+ import {
10
+ ConnectionStatus,
11
+ MykoClient,
12
+ type Command,
13
+ type CommandResult,
14
+ type QueryDiff,
15
+ type QueryItem,
16
+ type Query,
17
+ type ReportResult,
18
+ type Report
19
+ } from '@myko/core';
20
+ import { ref, shallowRef, shallowReactive, type Ref, type ShallowRef } from 'vue';
21
+ import { Subject, type Observable, type Subscription } from 'rxjs';
22
+
23
+ /** Command success event */
24
+ export type CommandSuccess = {
25
+ commandId: string;
26
+ response: unknown;
27
+ };
28
+
29
+ /** Command error event */
30
+ export type CommandError = {
31
+ commandId: string;
32
+ error: Error;
33
+ };
34
+
35
+ /** Reactive query result using reactive Map - generic over the Query factory type */
36
+ export type ReactiveQuery<Q extends Query<unknown>> = {
37
+ /** Reactive map of items by ID */
38
+ readonly items: Map<string, QueryItem<Q> & { id: string }>;
39
+ /** Whether the query has received its first response */
40
+ readonly resolved: Ref<boolean>;
41
+ /** Release this consumer's reference (unsubscribes when last consumer releases) */
42
+ release: () => void;
43
+ };
44
+
45
+ /** Reactive report result - generic over the Report factory type */
46
+ export type ReactiveReport<R extends Report<unknown>> = {
47
+ /** Current value (reactive via ref) */
48
+ readonly value: ShallowRef<ReportResult<R> | undefined>;
49
+ /** Release this consumer's reference (unsubscribes when last consumer releases) */
50
+ release: () => void;
51
+ };
52
+
53
+ /** Internal state for a shared query */
54
+ type SharedQuery<T extends { id: string }> = {
55
+ items: Map<string, T>;
56
+ resolved: Ref<boolean>;
57
+ subscription: Subscription;
58
+ refCount: number;
59
+ };
60
+
61
+ /** Internal state for a shared report */
62
+ type SharedReport<T> = {
63
+ value: ShallowRef<T | undefined>;
64
+ subscription: Subscription;
65
+ refCount: number;
66
+ };
67
+
68
+ /**
69
+ * Vue-friendly Myko client
70
+ *
71
+ * Wraps MykoClient to provide reactive Vue state with automatic deduplication.
72
+ */
73
+ export class VueMykoClient {
74
+ private client: MykoClient;
75
+
76
+ // Shared queries by cache key
77
+ private sharedQueries = new Map<string, SharedQuery<{ id: string }>>();
78
+
79
+ // Shared reports by cache key
80
+ private sharedReports = new Map<string, SharedReport<unknown>>();
81
+
82
+ // Command outcome subjects
83
+ private commandSuccessSubject = new Subject<CommandSuccess>();
84
+ private commandErrorSubject = new Subject<CommandError>();
85
+
86
+ /** Observable of all command successes */
87
+ readonly commandSuccess$: Observable<CommandSuccess> = this.commandSuccessSubject.asObservable();
88
+
89
+ /** Observable of all command errors */
90
+ readonly commandError$: Observable<CommandError> = this.commandErrorSubject.asObservable();
91
+
92
+ // Reactive connection status
93
+ private _connectionStatus = ref<ConnectionStatus>(ConnectionStatus.Disconnected);
94
+
95
+ constructor() {
96
+ this.client = new MykoClient();
97
+
98
+ // Sync connection status to reactive state
99
+ this.client.connectionStatus$.subscribe((status: ConnectionStatus) => {
100
+ this._connectionStatus.value = status;
101
+ });
102
+ }
103
+
104
+ /** Create a stable cache key from a query/report factory */
105
+ private getCacheKey(
106
+ type: 'query' | 'report',
107
+ factory: {
108
+ query?: Record<string, unknown>;
109
+ report?: Record<string, unknown>;
110
+ queryId?: string;
111
+ reportId?: string;
112
+ }
113
+ ): string {
114
+ const id = type === 'query' ? factory.queryId : factory.reportId;
115
+ const args = type === 'query' ? factory.query : factory.report;
116
+ return `${type}:${id}:${JSON.stringify(args)}`;
117
+ }
118
+
119
+ /** Current connection status (reactive) */
120
+ get connectionStatus(): Ref<ConnectionStatus> {
121
+ return this._connectionStatus;
122
+ }
123
+
124
+ /** Whether currently connected (reactive) - use .value to access */
125
+ get isConnected(): boolean {
126
+ return this._connectionStatus.value === ConnectionStatus.Connected;
127
+ }
128
+
129
+ /** Set the server address and connect */
130
+ connect(address: string): void {
131
+ this.client.setAddress(address);
132
+ }
133
+
134
+ /** Disconnect from the server */
135
+ disconnect(): void {
136
+ // Unsubscribe all shared queries
137
+ for (const shared of this.sharedQueries.values()) {
138
+ shared.subscription.unsubscribe();
139
+ }
140
+ this.sharedQueries.clear();
141
+
142
+ // Unsubscribe all shared reports
143
+ for (const shared of this.sharedReports.values()) {
144
+ shared.subscription.unsubscribe();
145
+ }
146
+ this.sharedReports.clear();
147
+
148
+ this.client.disconnect();
149
+ }
150
+
151
+ /**
152
+ * Watch a query with reactive Map updates.
153
+ *
154
+ * Multiple calls with the same query args share the same Map,
155
+ * and the subscription is only cancelled when all consumers release.
156
+ *
157
+ * @example
158
+ * ```vue
159
+ * <script setup>
160
+ * import { onUnmounted } from 'vue'
161
+ * const { items, resolved, release } = client.query(queries.GetAllTargets({}))
162
+ * onUnmounted(release)
163
+ * </script>
164
+ *
165
+ * <template>
166
+ * <div v-for="[id, target] in items" :key="id">{{ target.name }}</div>
167
+ * </template>
168
+ * ```
169
+ */
170
+ query<Q extends Query<unknown>>(queryFactory: Q): ReactiveQuery<Q> {
171
+ type Item = QueryItem<Q> & { id: string };
172
+ const cacheKey = this.getCacheKey('query', queryFactory);
173
+
174
+ // Return existing shared query if available
175
+ let shared = this.sharedQueries.get(cacheKey) as SharedQuery<Item> | undefined;
176
+
177
+ if (!shared) {
178
+ // Create new shared query with reactive Map
179
+ const items = shallowReactive(new Map<string, Item>());
180
+ const resolved = ref(false);
181
+
182
+ const subscription = this.client.watchQueryDiff(queryFactory).subscribe({
183
+ next: (diff) => {
184
+ if (diff.sequence === 0n) {
185
+ items.clear();
186
+ }
187
+ for (const id of diff.deletes) {
188
+ items.delete(id);
189
+ }
190
+ for (const item of diff.upserts as Item[]) {
191
+ items.set(item.id, item);
192
+ }
193
+ resolved.value = true;
194
+ }
195
+ });
196
+
197
+ shared = { items, resolved, subscription, refCount: 0 };
198
+ this.sharedQueries.set(cacheKey, shared as SharedQuery<{ id: string }>);
199
+ }
200
+
201
+ // Increment reference count
202
+ shared.refCount++;
203
+
204
+ let released = false;
205
+
206
+ return {
207
+ items: shared.items,
208
+ resolved: shared.resolved,
209
+ release: () => {
210
+ if (released) return;
211
+ released = true;
212
+
213
+ const s = this.sharedQueries.get(cacheKey);
214
+ if (s) {
215
+ s.refCount--;
216
+ if (s.refCount <= 0) {
217
+ s.subscription.unsubscribe();
218
+ this.sharedQueries.delete(cacheKey);
219
+ }
220
+ }
221
+ }
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Watch a report with reactive value updates.
227
+ *
228
+ * Multiple calls with the same report args share the same subscription,
229
+ * and the subscription is only cancelled when all consumers release.
230
+ *
231
+ * @example
232
+ * ```vue
233
+ * <script setup>
234
+ * import { onUnmounted } from 'vue'
235
+ * const { value, release } = client.report(reports.CountAllTargets({}))
236
+ * onUnmounted(release)
237
+ * </script>
238
+ *
239
+ * <template>
240
+ * <div>Count: {{ value?.count ?? 'loading...' }}</div>
241
+ * </template>
242
+ * ```
243
+ */
244
+ report<R extends Report<unknown>>(reportFactory: R): ReactiveReport<R> {
245
+ type Result = ReportResult<R>;
246
+ const cacheKey = this.getCacheKey('report', reportFactory);
247
+
248
+ // Return existing shared report if available
249
+ let shared = this.sharedReports.get(cacheKey) as SharedReport<Result> | undefined;
250
+
251
+ if (!shared) {
252
+ // Create new shared report with reactive state
253
+ const value = shallowRef<Result | undefined>(undefined);
254
+ const subscription = this.client.watchReport(reportFactory).subscribe({
255
+ next: (result) => {
256
+ value.value = result;
257
+ }
258
+ });
259
+
260
+ shared = {
261
+ value: value as ShallowRef<Result | undefined>,
262
+ subscription,
263
+ refCount: 0
264
+ };
265
+ this.sharedReports.set(cacheKey, shared as SharedReport<unknown>);
266
+ }
267
+
268
+ // Increment reference count (shared is guaranteed to be defined here)
269
+ shared!.refCount++;
270
+
271
+ let released = false;
272
+
273
+ return {
274
+ value: shared!.value as ShallowRef<Result | undefined>,
275
+ release: () => {
276
+ if (released) return;
277
+ released = true;
278
+
279
+ const s = this.sharedReports.get(cacheKey);
280
+ if (s) {
281
+ s.refCount--;
282
+ if (s.refCount <= 0) {
283
+ s.subscription.unsubscribe();
284
+ this.sharedReports.delete(cacheKey);
285
+ }
286
+ }
287
+ }
288
+ };
289
+ }
290
+
291
+ /**
292
+ * Send a command and wait for the response.
293
+ *
294
+ * Emits to commandSuccess$ or commandError$ observables for generic handling.
295
+ *
296
+ * @example
297
+ * ```vue
298
+ * <script setup>
299
+ * async function deleteMachine(id: string) {
300
+ * const result = await myko.sendCommand(commands.DeleteMachine({ machineId: id }))
301
+ * console.log('Deleted:', result)
302
+ * }
303
+ * </script>
304
+ * ```
305
+ */
306
+ async sendCommand<C extends Command<unknown>>(
307
+ commandFactory: C
308
+ ): Promise<CommandResult<C>> {
309
+ const commandId = commandFactory.commandId;
310
+ try {
311
+ const response = await this.client.sendCommand(commandFactory);
312
+ this.commandSuccessSubject.next({ commandId, response });
313
+ return response;
314
+ } catch (e) {
315
+ const error = e instanceof Error ? e : new Error(String(e));
316
+ this.commandErrorSubject.next({ commandId, error });
317
+ throw e;
318
+ }
319
+ }
320
+
321
+ /** Access the underlying MykoClient for advanced use cases */
322
+ get raw(): MykoClient {
323
+ return this.client;
324
+ }
325
+ }
326
+
327
+ /** Global singleton client instance (auto-initialized) */
328
+ export const myko = new VueMykoClient();
329
+
330
+ // HMR cleanup - disconnect old client when module is hot-reloaded
331
+ if (import.meta.hot) {
332
+ import.meta.hot.dispose(() => {
333
+ myko.disconnect();
334
+ });
335
+ }
336
+
337
+ /** Get the global MykoClient instance */
338
+ export function getMykoClient(): VueMykoClient {
339
+ return myko;
340
+ }
341
+
342
+ /** Create a new VueMykoClient instance (non-singleton, for advanced use) */
343
+ export function createMykoClient(): VueMykoClient {
344
+ return new VueMykoClient();
345
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "jsx": "preserve",
8
+ "resolveJsonModule": true,
9
+ "isolatedModules": true,
10
+ "esModuleInterop": true,
11
+ "lib": ["ESNext", "DOM"],
12
+ "skipLibCheck": true,
13
+ "noEmit": true,
14
+ "types": ["vite/client"]
15
+ },
16
+ "include": ["src/**/*.ts", "src/**/*.vue"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite';
2
+ import vue from '@vitejs/plugin-vue';
3
+
4
+ export default defineConfig({
5
+ plugins: [vue()]
6
+ });