sse-stream-plugin-vue 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/dist/index.cjs +87 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.mjs +85 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ryan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# sse-stream-plugin-vue
|
|
2
|
+
|
|
3
|
+
[sse-stream-plugin-sdk](../core) 的 Vue 3 Composable 封装。将插件化 SSE SDK 封装为响应式 API,支持 `MaybeRef` 入参与自动生命周期管理。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
需要同时安装核心 SDK:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install sse-stream-plugin-vue sse-stream-plugin-sdk
|
|
11
|
+
# 或
|
|
12
|
+
pnpm add sse-stream-plugin-vue sse-stream-plugin-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> `vue` 为 peerDependency,要求 `>=3.2.0`。
|
|
16
|
+
|
|
17
|
+
## 快速开始
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { ref } from 'vue'
|
|
22
|
+
import { useSSEStream } from 'sse-stream-plugin-vue'
|
|
23
|
+
import { recommendedPlugins } from 'sse-stream-plugin-sdk'
|
|
24
|
+
|
|
25
|
+
const prompt = ref('你好')
|
|
26
|
+
|
|
27
|
+
const { text, loading, status, start, stop } = useSSEStream({
|
|
28
|
+
url: 'https://api.example.com/stream',
|
|
29
|
+
method: 'POST',
|
|
30
|
+
// getBody 每次 start 时调用,读取最新 prompt
|
|
31
|
+
getBody: () => JSON.stringify({ prompt: prompt.value }),
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
plugins: recommendedPlugins(),
|
|
34
|
+
onMessage: (data) => console.log(data),
|
|
35
|
+
onError: (err) => console.error(err),
|
|
36
|
+
})
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<input v-model="prompt" />
|
|
42
|
+
<button @click="start" :disabled="loading">发送</button>
|
|
43
|
+
<button @click="stop">停止</button>
|
|
44
|
+
<p>{{ status }}</p>
|
|
45
|
+
<pre>{{ text }}</pre>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `useSSEStream(options)`
|
|
53
|
+
|
|
54
|
+
#### 入参 `UseSSEStreamOptions`
|
|
55
|
+
|
|
56
|
+
核心配置字段支持 `MaybeRef`(可传 `ref` 或原始值),`start` 时 `unref` 读取最新值:
|
|
57
|
+
|
|
58
|
+
| 字段 | 类型 | 说明 |
|
|
59
|
+
|------|------|------|
|
|
60
|
+
| `url` | `MaybeRef<string>` | 请求地址(必填) |
|
|
61
|
+
| `method` | `MaybeRef<'GET' \| 'POST'>` | 请求方法,默认 `GET` |
|
|
62
|
+
| `body` | `MaybeRef<string>` | 请求体字符串 |
|
|
63
|
+
| `getBody` | `() => string` | 每次 `start` 时动态生成请求体,优先级高于 `body` |
|
|
64
|
+
| `headers` | `MaybeRef<Record<string, string>>` | 自定义请求头 |
|
|
65
|
+
| `transport` | `MaybeRef<string \| TransportFactory>` | 传输层,省略则自动探测 `fetch` |
|
|
66
|
+
| `parser` | `MaybeRef<ParserFactory>` | 自定义解析器 |
|
|
67
|
+
| `plugins` | `MaybeRef<SSEPlugin[]>` | 插件列表 |
|
|
68
|
+
| `onMessage` | `(data, event) => void` | 收到 message 事件回调 |
|
|
69
|
+
| `onOpen` | `(info: { transport }) => void` | 连接打开回调 |
|
|
70
|
+
| `onEnd` | `() => void` | 流结束回调 |
|
|
71
|
+
| `onError` | `(err) => void` | 错误回调 |
|
|
72
|
+
|
|
73
|
+
#### 返回值 `UseSSEStreamReturn`
|
|
74
|
+
|
|
75
|
+
状态字段均为只读 `Ref`:
|
|
76
|
+
|
|
77
|
+
| 字段 | 类型 | 说明 |
|
|
78
|
+
|------|------|------|
|
|
79
|
+
| `text` | `Readonly<Ref<string>>` | 已拼接的消息文本(`message` 事件 `data` 累加) |
|
|
80
|
+
| `status` | `Readonly<Ref<string>>` | 连接状态描述 |
|
|
81
|
+
| `loading` | `Readonly<Ref<boolean>>` | 是否处于连接中/流式接收中 |
|
|
82
|
+
| `msgCount` | `Readonly<Ref<number>>` | 已接收 message 事件条数 |
|
|
83
|
+
| `charCount` | `Readonly<Ref<number>>` | 已接收字符总数 |
|
|
84
|
+
| `start` | `() => void` | 发起一次连接(先销毁旧连接) |
|
|
85
|
+
| `stop` | `() => void` | 手动断开并销毁实例 |
|
|
86
|
+
| `instance` | `Ref<PluginSSE \| null>` | 当前实例(`shallowRef`,便于 `use()` 追加插件) |
|
|
87
|
+
|
|
88
|
+
## 生命周期
|
|
89
|
+
|
|
90
|
+
- 组件卸载时(`onBeforeUnmount`)自动 `destroy()` 实例并清空订阅,无需手动清理
|
|
91
|
+
- `start()` 会先销毁旧连接再创建新连接,可重复调用
|
|
92
|
+
|
|
93
|
+
## 高级用法
|
|
94
|
+
|
|
95
|
+
### 响应式 url
|
|
96
|
+
|
|
97
|
+
```vue
|
|
98
|
+
<script setup lang="ts">
|
|
99
|
+
import { ref } from 'vue'
|
|
100
|
+
|
|
101
|
+
const url = ref('https://api.example.com/stream')
|
|
102
|
+
|
|
103
|
+
const { start } = useSSEStream({
|
|
104
|
+
url, // 传 ref,start 时自动取最新值
|
|
105
|
+
method: 'POST',
|
|
106
|
+
})
|
|
107
|
+
</script>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 通过 `instance` 追加插件
|
|
111
|
+
|
|
112
|
+
```vue
|
|
113
|
+
<script setup lang="ts">
|
|
114
|
+
import { watch } from 'vue'
|
|
115
|
+
import { loggerPlugin } from 'sse-stream-plugin-sdk'
|
|
116
|
+
|
|
117
|
+
const { instance } = useSSEStream({ url, method: 'POST' })
|
|
118
|
+
|
|
119
|
+
watch(instance, (sse) => {
|
|
120
|
+
if (sse) sse.use(loggerPlugin())
|
|
121
|
+
})
|
|
122
|
+
</script>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 小程序环境
|
|
126
|
+
|
|
127
|
+
通过 `transport` 传入小程序传输层工厂:
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<script setup lang="ts">
|
|
131
|
+
import { createMpTransport } from 'sse-stream-plugin-sdk'
|
|
132
|
+
|
|
133
|
+
const { start } = useSSEStream({
|
|
134
|
+
url,
|
|
135
|
+
transport: createMpTransport(() => wx),
|
|
136
|
+
})
|
|
137
|
+
</script>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vue = require('vue');
|
|
4
|
+
var sseStreamPluginSdk = require('sse-stream-plugin-sdk');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @file Vue3 Composable:将插件化 SSE SDK 封装为响应式 API
|
|
8
|
+
* @description
|
|
9
|
+
* - 实例用 shallowRef 持有,避免对命令式对象做深度代理;
|
|
10
|
+
* - start() 内按需创建 PluginSSE,组件卸载时自动 destroy();
|
|
11
|
+
* - 入参支持 MaybeRef,start 时 unref 读取最新值,适配响应式 url/prompt;
|
|
12
|
+
* - 暴露只读 ref 状态与 start/stop 方法。
|
|
13
|
+
*/
|
|
14
|
+
function useSSEStream(options) {
|
|
15
|
+
const text = vue.ref('');
|
|
16
|
+
const status = vue.ref('未连接');
|
|
17
|
+
const loading = vue.ref(false);
|
|
18
|
+
const msgCount = vue.ref(0);
|
|
19
|
+
const charCount = vue.ref(0);
|
|
20
|
+
const instance = vue.shallowRef(null);
|
|
21
|
+
function stop() {
|
|
22
|
+
instance.value?.destroy();
|
|
23
|
+
instance.value = null;
|
|
24
|
+
status.value = '已手动断开';
|
|
25
|
+
loading.value = false;
|
|
26
|
+
}
|
|
27
|
+
function start() {
|
|
28
|
+
const { url, method, body, headers, transport, parser, plugins, getBody, onMessage, onOpen, onEnd, onError, } = options;
|
|
29
|
+
// 销毁旧连接
|
|
30
|
+
instance.value?.destroy();
|
|
31
|
+
text.value = '';
|
|
32
|
+
msgCount.value = 0;
|
|
33
|
+
charCount.value = 0;
|
|
34
|
+
status.value = '连接中…';
|
|
35
|
+
loading.value = true;
|
|
36
|
+
const sse = new sseStreamPluginSdk.PluginSSE({
|
|
37
|
+
url: vue.unref(url),
|
|
38
|
+
method: vue.unref(method) ?? 'GET',
|
|
39
|
+
body: getBody ? getBody() : vue.unref(body),
|
|
40
|
+
headers: vue.unref(headers),
|
|
41
|
+
transport: vue.unref(transport),
|
|
42
|
+
parser: vue.unref(parser),
|
|
43
|
+
plugins: vue.unref(plugins),
|
|
44
|
+
});
|
|
45
|
+
sse.on('open', ({ transport: name }) => {
|
|
46
|
+
status.value = `已连接(${name})`;
|
|
47
|
+
onOpen?.({ transport: name });
|
|
48
|
+
});
|
|
49
|
+
sse.on('message', (data, event) => {
|
|
50
|
+
text.value += data;
|
|
51
|
+
msgCount.value += 1;
|
|
52
|
+
charCount.value += data.length;
|
|
53
|
+
onMessage?.(data, event);
|
|
54
|
+
});
|
|
55
|
+
sse.on('end', () => {
|
|
56
|
+
status.value = '流正常结束';
|
|
57
|
+
loading.value = false;
|
|
58
|
+
onEnd?.();
|
|
59
|
+
});
|
|
60
|
+
sse.on('error', (err) => {
|
|
61
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
62
|
+
status.value = `错误:${msg}`;
|
|
63
|
+
loading.value = false;
|
|
64
|
+
onError?.(err);
|
|
65
|
+
});
|
|
66
|
+
instance.value = sse;
|
|
67
|
+
sse.connect();
|
|
68
|
+
}
|
|
69
|
+
// 组件卸载:释放连接、清空订阅
|
|
70
|
+
vue.onBeforeUnmount(() => {
|
|
71
|
+
instance.value?.destroy();
|
|
72
|
+
instance.value = null;
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
text: vue.readonly(text),
|
|
76
|
+
status: vue.readonly(status),
|
|
77
|
+
loading: vue.readonly(loading),
|
|
78
|
+
msgCount: vue.readonly(msgCount),
|
|
79
|
+
charCount: vue.readonly(charCount),
|
|
80
|
+
start,
|
|
81
|
+
stop,
|
|
82
|
+
instance,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
exports.useSSEStream = useSSEStream;
|
|
87
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/useSSEStream.ts"],"sourcesContent":[null],"names":["ref","shallowRef","PluginSSE","unref","onBeforeUnmount","readonly"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MaybeRef, Ref } from 'vue';
|
|
2
|
+
import { PluginSSEOptions, ParsedEvent, PluginSSE } from 'sse-stream-plugin-sdk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file Vue3 Composable:将插件化 SSE SDK 封装为响应式 API
|
|
6
|
+
* @description
|
|
7
|
+
* - 实例用 shallowRef 持有,避免对命令式对象做深度代理;
|
|
8
|
+
* - start() 内按需创建 PluginSSE,组件卸载时自动 destroy();
|
|
9
|
+
* - 入参支持 MaybeRef,start 时 unref 读取最新值,适配响应式 url/prompt;
|
|
10
|
+
* - 暴露只读 ref 状态与 start/stop 方法。
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
type CoreFields = Pick<PluginSSEOptions, 'url' | 'method' | 'body' | 'headers' | 'transport' | 'parser' | 'plugins'>;
|
|
14
|
+
/**
|
|
15
|
+
* Composable 入参:核心配置支持 MaybeRef(可传 ref 或原始值),
|
|
16
|
+
* 配合动态 body 与事件回调。
|
|
17
|
+
*/
|
|
18
|
+
interface UseSSEStreamOptions {
|
|
19
|
+
url: MaybeRef<CoreFields['url']>;
|
|
20
|
+
method?: MaybeRef<CoreFields['method']>;
|
|
21
|
+
body?: MaybeRef<CoreFields['body']>;
|
|
22
|
+
headers?: MaybeRef<CoreFields['headers']>;
|
|
23
|
+
transport?: MaybeRef<CoreFields['transport']>;
|
|
24
|
+
parser?: MaybeRef<CoreFields['parser']>;
|
|
25
|
+
plugins?: MaybeRef<CoreFields['plugins']>;
|
|
26
|
+
/** 每次 start 时动态生成请求体,优先级高于 body */
|
|
27
|
+
getBody?: () => string;
|
|
28
|
+
onMessage?: (data: string, event: ParsedEvent) => void;
|
|
29
|
+
onOpen?: (info: {
|
|
30
|
+
transport: string;
|
|
31
|
+
}) => void;
|
|
32
|
+
onEnd?: () => void;
|
|
33
|
+
onError?: (err: unknown) => void;
|
|
34
|
+
}
|
|
35
|
+
interface UseSSEStreamReturn {
|
|
36
|
+
text: Ref<string>;
|
|
37
|
+
status: Ref<string>;
|
|
38
|
+
loading: Ref<boolean>;
|
|
39
|
+
msgCount: Ref<number>;
|
|
40
|
+
charCount: Ref<number>;
|
|
41
|
+
start: () => void;
|
|
42
|
+
stop: () => void;
|
|
43
|
+
instance: Ref<PluginSSE | null>;
|
|
44
|
+
}
|
|
45
|
+
declare function useSSEStream(options: UseSSEStreamOptions): UseSSEStreamReturn;
|
|
46
|
+
|
|
47
|
+
export { useSSEStream };
|
|
48
|
+
export type { UseSSEStreamOptions, UseSSEStreamReturn };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ref, shallowRef, onBeforeUnmount, readonly, unref } from 'vue';
|
|
2
|
+
import { PluginSSE } from 'sse-stream-plugin-sdk';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file Vue3 Composable:将插件化 SSE SDK 封装为响应式 API
|
|
6
|
+
* @description
|
|
7
|
+
* - 实例用 shallowRef 持有,避免对命令式对象做深度代理;
|
|
8
|
+
* - start() 内按需创建 PluginSSE,组件卸载时自动 destroy();
|
|
9
|
+
* - 入参支持 MaybeRef,start 时 unref 读取最新值,适配响应式 url/prompt;
|
|
10
|
+
* - 暴露只读 ref 状态与 start/stop 方法。
|
|
11
|
+
*/
|
|
12
|
+
function useSSEStream(options) {
|
|
13
|
+
const text = ref('');
|
|
14
|
+
const status = ref('未连接');
|
|
15
|
+
const loading = ref(false);
|
|
16
|
+
const msgCount = ref(0);
|
|
17
|
+
const charCount = ref(0);
|
|
18
|
+
const instance = shallowRef(null);
|
|
19
|
+
function stop() {
|
|
20
|
+
instance.value?.destroy();
|
|
21
|
+
instance.value = null;
|
|
22
|
+
status.value = '已手动断开';
|
|
23
|
+
loading.value = false;
|
|
24
|
+
}
|
|
25
|
+
function start() {
|
|
26
|
+
const { url, method, body, headers, transport, parser, plugins, getBody, onMessage, onOpen, onEnd, onError, } = options;
|
|
27
|
+
// 销毁旧连接
|
|
28
|
+
instance.value?.destroy();
|
|
29
|
+
text.value = '';
|
|
30
|
+
msgCount.value = 0;
|
|
31
|
+
charCount.value = 0;
|
|
32
|
+
status.value = '连接中…';
|
|
33
|
+
loading.value = true;
|
|
34
|
+
const sse = new PluginSSE({
|
|
35
|
+
url: unref(url),
|
|
36
|
+
method: unref(method) ?? 'GET',
|
|
37
|
+
body: getBody ? getBody() : unref(body),
|
|
38
|
+
headers: unref(headers),
|
|
39
|
+
transport: unref(transport),
|
|
40
|
+
parser: unref(parser),
|
|
41
|
+
plugins: unref(plugins),
|
|
42
|
+
});
|
|
43
|
+
sse.on('open', ({ transport: name }) => {
|
|
44
|
+
status.value = `已连接(${name})`;
|
|
45
|
+
onOpen?.({ transport: name });
|
|
46
|
+
});
|
|
47
|
+
sse.on('message', (data, event) => {
|
|
48
|
+
text.value += data;
|
|
49
|
+
msgCount.value += 1;
|
|
50
|
+
charCount.value += data.length;
|
|
51
|
+
onMessage?.(data, event);
|
|
52
|
+
});
|
|
53
|
+
sse.on('end', () => {
|
|
54
|
+
status.value = '流正常结束';
|
|
55
|
+
loading.value = false;
|
|
56
|
+
onEnd?.();
|
|
57
|
+
});
|
|
58
|
+
sse.on('error', (err) => {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
status.value = `错误:${msg}`;
|
|
61
|
+
loading.value = false;
|
|
62
|
+
onError?.(err);
|
|
63
|
+
});
|
|
64
|
+
instance.value = sse;
|
|
65
|
+
sse.connect();
|
|
66
|
+
}
|
|
67
|
+
// 组件卸载:释放连接、清空订阅
|
|
68
|
+
onBeforeUnmount(() => {
|
|
69
|
+
instance.value?.destroy();
|
|
70
|
+
instance.value = null;
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
text: readonly(text),
|
|
74
|
+
status: readonly(status),
|
|
75
|
+
loading: readonly(loading),
|
|
76
|
+
msgCount: readonly(msgCount),
|
|
77
|
+
charCount: readonly(charCount),
|
|
78
|
+
start,
|
|
79
|
+
stop,
|
|
80
|
+
instance,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { useSSEStream };
|
|
85
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/useSSEStream.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sse-stream-plugin-vue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vue 3 composables for sse-stream-plugin-sdk",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"sse",
|
|
9
|
+
"server-sent-events",
|
|
10
|
+
"stream",
|
|
11
|
+
"vue",
|
|
12
|
+
"composable"
|
|
13
|
+
],
|
|
14
|
+
"main": "dist/index.cjs",
|
|
15
|
+
"module": "dist/index.mjs",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.mjs",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "rollup -c",
|
|
31
|
+
"build:prod": "rollup -c --environment NODE_ENV:production"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"vue": ">=3.2.0",
|
|
35
|
+
"sse-stream-plugin-sdk": "^1.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"sse-stream-plugin-sdk": "workspace:*",
|
|
39
|
+
"vue": "^3.5.42"
|
|
40
|
+
}
|
|
41
|
+
}
|