sse-stream-plugin-sdk 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -996
- package/dist/index.umd.js +1 -1018
- package/dist/package.json +3 -0
- package/package.json +3 -3
- package/dist/index.cjs +0 -1012
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/index.umd.js.map +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";class e{constructor(){Object.defineProperty(this,"listeners",{enumerable:!0,configurable:!0,writable:!0,value:new Map})}on(e,t){let r=this.listeners.get(e);return r||(r=new Set,this.listeners.set(e,r)),r.add(t),()=>this.off(e,t)}once(e,t){const r=this.on(e,(...e)=>{r(),t(...e)});return r}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,...t){const r=this.listeners.get(e);if(r)for(const e of[...r])e(...t)}clear(){this.listeners.clear()}}function t(){let e="";return{write:(t,s)=>{e+=t;const n=e.replace(/\r\n?/g,"\n").split("\n\n");e=n.pop()??"";for(const e of n){if(!e.trim())continue;const t=r(e);t&&s(t)}},flush:t=>{const s=e.replace(/\r\n?/g,"\n").trim();if(e="",!s)return;const n=r(s);n&&t(n)}}}function r(e){let t="message";const r=[];let s,n=!1;for(const i of e.split("\n")){if(!i||i.startsWith(":"))continue;const e=i.indexOf(":");let o,a;switch(-1===e?(o=i,a=""):(o=i.slice(0,e),a=i.slice(e+1)," "===a.charAt(0)&&(a=a.slice(1))),o){case"event":t=a;break;case"data":r.push(a);break;case"id":a.includes("\0")||(s=a,n=!0)}}return 0===r.length?null:{name:t,data:r.join("\n"),...n?{id:s}:{}}}const s=()=>{let e=null,t=!1;return{name:"web-fetch",async connect(r,s){try{const i=await fetch(r.url,{method:r.method,headers:{"Content-Type":"application/json",...r.headers},body:"POST"===r.method?r.body:void 0});if(s.response?.({status:i.status,headers:n(i.headers)}),!i.ok||!i.body)throw new Error(`HTTP ${i.status} 流不可用`);e=i.body.getReader();const o=new TextDecoder("utf-8");for(;;){const{done:r,value:n}=await e.read();if(t)break;if(r){s.end();break}s.data(o.decode(n,{stream:!0}))}}catch(e){t||s.error(e)}},abort(){t=!0,e?.cancel().catch(()=>{}),e=null}}};function n(e){const t={};return e.forEach((e,r)=>{t[r]=e}),t}function i(){return[{id:"m1",data:"开始解释:\n"},{id:"m2",data:"输入内容:你好\n"},{name:"ping",data:"",gap:200},{id:"m3",data:"\n1. 语法解析完成"},{id:"m4",data:"\n2. 语义分析完成"},{id:"m5",data:"\n3. 生成解释结果"},{id:"m6",data:"\n✅ 解释完毕"}]}function o(e){const t=e?.events??[{id:"m1",data:"开始解释:\n"},{id:"m2",data:"输入内容:你好\n"},{name:"ping",data:"",gap:200},{id:"m3",data:"\n1. 语法解析完成"},{id:"m4",data:"\n2. 语义分析完成"},{id:"m5",data:"\n3. 生成解释结果"},{id:"m6",data:"\n✅ 解释完毕"}],r=e?.failAfter??0,s=e?.errorMessage??"模拟网络中断(连接被重置)";let n=!1;return({request:e})=>{const i=[];let o=!1,a=0;const l=e.headers["Last-Event-ID"]??e.headers["last-event-id"];if(l){const e=t.findIndex(e=>e.id===l);e>=0&&(a=e+1)}return{name:"mock",connect(e,l){const c=()=>{if(o)return;if(r>0&&a===r&&!n){n=!0;const e=setTimeout(()=>{o||l.error(new Error(s))},500);return void i.push(e)}if(a>=t.length){const e=setTimeout(()=>{o||l.end()},200);return void i.push(e)}const e=t[a],d=setTimeout(()=>{o||(l.data(function(e){const t=[];e.id&&t.push(`id:${e.id}`);t.push(`event:${e.name??"message"}`);for(const r of(e.data??"").split("\n"))t.push(`data:${r}`);return t.join("\n")+"\n\n"}(e)),a++,c())},e.gap??350);i.push(d)};c()},abort(){o=!0;for(const e of i)clearTimeout(e);i.length=0}}}}function a(){if("function"==typeof globalThis.fetch)return s;throw new Error("未检测到可用传输层,请通过 options.transport 显式指定,或用 createMpTransport 注册小程序传输层")}function l(e){const t=e?.maxRetries??3,r=e?.delay??1500;let s="",n=0,i=null;return{name:"reconnect",install(e){e.addRequestMiddleware(async(e,t)=>(s&&(e.headers["Last-Event-ID"]=s),t(e))),e.emitter.on("event",e=>{e.id&&(s=e.id)}),e.emitter.on("error",s=>{e.isDead()||(n>=t?e.emitter.emit("reconnect-failed",s):(n++,e.emitter.emit("reconnect",{attempt:n,inMs:r}),i=setTimeout(()=>{i=null,e.start()},r)))}),e.emitter.on("end",()=>{n=0,s=""}),e.onDispose(()=>{i&&clearTimeout(i),i=null})}}}function c(e){const t=e?.interval??1e4;let r=null;return{name:"heartbeat",install(e){const s=()=>{r&&(clearTimeout(r),r=null)},n=()=>{s(),r=setTimeout(()=>{e.emitter.emit("heartbeat-lost"),e.fail(new Error(`心跳丢失:${t}ms 内未收到任何数据`))},t)};e.emitter.on("connecting",n),e.emitter.on("data",n),e.emitter.on("end",s),e.emitter.on("error",s),e.onDispose(s)}}}function d(e){const t=e?.windowMs??100;let r,s="",n=null,i=null;return{name:"throttle",install(e){const o=()=>{if(n&&(clearTimeout(n),n=null),s&&i){const e=s,t=r;s="",r=void 0;const n=i;i=null,n({name:"message",data:e,...t?{id:t}:{}})}};e.addEventMiddleware((e,a)=>{if("message"!==e.name)return a(e);s+=e.data,e.id&&(r=e.id),i=a,n||(n=setTimeout(o,t))}),e.emitter.on("end",o),e.emitter.on("error",o),e.onDispose(o)}}}exports.Emitter=e,exports.PluginSSE=class{constructor(r){Object.defineProperty(this,"emitter",{enumerable:!0,configurable:!0,writable:!0,value:new e}),Object.defineProperty(this,"plugins",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"installed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"context",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"transportRegistry",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"requestMiddleware",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"eventMiddleware",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"disposeFns",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"parserFactory",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"parser",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"activeTransport",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"currentRequest",{enumerable:!0,configurable:!0,writable:!0,value:{url:"",method:"GET",headers:{}}}),Object.defineProperty(this,"options",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"state",{enumerable:!0,configurable:!0,writable:!0,value:"idle"}),Object.defineProperty(this,"sessionId",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"dead",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"dispatch",{enumerable:!0,configurable:!0,writable:!0,value:e=>{!function(e,t,r,s){let n=-1;const i=(t,s)=>{if(t<=n)return Promise.reject(new Error("next() 被多次调用"));if(n=t,t===e.length)return r(s),Promise.resolve();try{return Promise.resolve(e[t](s,e=>i(t+1,e??s)))}catch(e){return Promise.reject(e)}};i(0,t).catch(s)}(this.eventMiddleware,e,e=>{this.emitter.emit("event",e),this.emitter.emit(e.name,e.data,e)},e=>this.settleError(e))}}),this.options={url:r.url,method:r.method??"GET",body:r.body??"",headers:r.headers??{},transport:r.transport,plugins:r.plugins??[],parser:r.parser},this.options.parser&&(this.parserFactory=this.options.parser),this.transportRegistry.set("web",s),this.transportRegistry.set("mock",o());const n=this;this.context={emitter:this.emitter,get request(){return n.currentRequest},addRequestMiddleware:e=>this.requestMiddleware.push(e),addEventMiddleware:e=>this.eventMiddleware.push(e),setParser:e=>{this.parserFactory=e},registerTransport:(e,t)=>this.transportRegistry.set(e,t),start:()=>this.start(),fail:e=>this.settleError(e),getState:()=>this.state,isDead:()=>this.dead,onDispose:e=>this.disposeFns.push(e)};for(const e of this.options.plugins)this.use(e)}use(e){if(this.dead)throw new Error("实例已销毁,无法再注册插件");return this.plugins.some(t=>t.name===e.name)||(this.plugins.push(e),this.installed&&e.install(this.context)),this}async connect(){if(this.dead)throw new Error("实例已销毁,请创建新的 PluginSSE");await this.start()}async start(){if(this.dead)return;this.installed||this.installPlugins(),this.silentAbort();const e=++this.sessionId;let t;this.state="connecting",this.currentRequest={url:this.options.url,method:this.options.method,headers:{...this.options.headers},body:"POST"===this.options.method?this.options.body:void 0},this.emitter.emit("connecting",{session:e});try{t=await(r=this.requestMiddleware,e=>{let t=-1;const s=(e,n)=>{if(e<=t)return Promise.reject(new Error("next() 被多次调用"));if(t=e,e===r.length)return Promise.resolve(n);try{return Promise.resolve(r[e](n,t=>s(e+1,t??n)))}catch(e){return Promise.reject(e)}};return s(0,e)})(this.currentRequest)}catch(t){return void(e===this.sessionId&&this.settleError(t))}var r;if(e!==this.sessionId||this.dead)return;this.currentRequest=t,this.parser=this.parserFactory();const s=this.resolveTransportFactory()({request:t});this.activeTransport=s,s.connect(t,{data:t=>{e===this.sessionId&&(this.emitter.emit("data",t),this.parser?.write(t,this.dispatch))},end:()=>{e===this.sessionId&&(this.parser?.flush(this.dispatch),this.state="closed",this.emitter.emit("end"))},error:t=>{e===this.sessionId&&this.settleError(t)},response:t=>{e===this.sessionId&&this.emitter.emit("response",t)}}),this.state="open",this.emitter.emit("open",{transport:s.name})}destroy(){if(!this.dead){this.dead=!0,this.sessionId++,this.silentAbort(),this.state="closed";for(const e of this.disposeFns)try{e()}catch{}this.emitter.emit("closed"),this.emitter.clear()}}on(e,t){return this.emitter.on(e,t)}once(e,t){return this.emitter.once(e,t)}off(e,t){this.emitter.off(e,t)}installPlugins(){this.installed=!0;for(const e of this.plugins)e.install(this.context)}resolveTransportFactory(){const e=this.options.transport;if("string"==typeof e){const t=this.transportRegistry.get(e);if(!t)throw new Error(`未注册的传输层:${e}`);return t}return e||a()}settleError(e){this.dead||(this.sessionId++,this.silentAbort(),this.state="closed",this.emitter.emit("error",e))}silentAbort(){if(this.activeTransport){try{this.activeTransport.abort()}catch{}this.activeTransport=null}}},exports.authPlugin=function(e){const t=e.header??"Authorization",r=e.scheme??"Bearer";let s=!1;return{name:"auth",install(n){n.addRequestMiddleware(async(s,n)=>{const i=await e.getToken();return s.headers[t]=r?`${r} ${i}`:i,n(s)}),n.emitter.on("response",async({status:t})=>{if(401===t&&!s&&!n.isDead()){s=!0,n.emitter.emit("auth-refreshing");try{await e.refreshToken()}finally{s=!1}n.start()}})}}},exports.createMpTransport=function(e,t="miniprogram"){return()=>{let r,s=null,n=!1;return{name:t,connect(t,i){const o=e();s=o.request({url:t.url,method:t.method,header:{...t.headers},data:"POST"===t.method&&t.body?JSON.parse(t.body):void 0,enableChunked:!0,responseType:"arraybuffer",success:e=>{n||(i.response?.({status:e.statusCode}),i.end())},fail:e=>{n||i.error(function(e){if(e instanceof Error)return e;if(null!==e&&"object"==typeof e&&"errMsg"in e){const t=e.errMsg;return new Error("string"==typeof t&&t?t:"request 失败")}return new Error(String(e))}(e))}}),s.onChunkReceived(e=>{n||i.data(function(e){void 0===r&&(r="undefined"!=typeof TextDecoder?new TextDecoder("utf-8"):null);if(r)return r.decode(e,{stream:!0});let t="";for(let r=0;r<e.length;r++)t+="%"+e[r].toString(16).padStart(2,"0");return decodeURIComponent(t)}(new Uint8Array(e.data)))})},abort(){n=!0,s?.abort(),s=null}}}},exports.createSSEParser=t,exports.defaultScript=i,exports.detectTransport=a,exports.heartbeatPlugin=c,exports.loggerPlugin=function(e){const t=e?.sink??(e=>console.log(e));return{name:"logger",install(e){e.emitter.on("open",({transport:r})=>{const s=JSON.stringify(e.request.headers);t(`连接已打开(${r})请求头:${s}`)}),e.emitter.on("response",({status:e})=>{t(`收到响应,状态码:${e}`)}),e.emitter.on("event",e=>{const r=e.data.replace(/\n/g,"\\n"),s=r.length>40?r.slice(0,40)+"…":r;t(`事件 ${e.name}${e.id?" #"+e.id:""} (${e.data.length} 字): ${s}`)}),e.emitter.on("reconnect",({attempt:e,inMs:r})=>{t(`连接中断,${r}ms 后进行第 ${e} 次重连…`)}),e.emitter.on("heartbeat-lost",()=>{t("心跳丢失!")}),e.emitter.on("reconnect-failed",()=>{t("已达最大重试次数,不再重连")}),e.emitter.on("error",e=>{t(`发生错误:${e instanceof Error?e.message:String(e)}`)}),e.emitter.on("end",()=>{t("流正常结束")}),e.emitter.on("closed",()=>{t("实例已销毁,资源已释放")})}}},exports.mockTransport=o,exports.recommendedPlugins=function(){return[l(),c(),d()]},exports.reconnectPlugin=l,exports.statsPlugin=function(e){const t=e?.keyword??"✅";return{name:"stats",install(e){let r=0,s=0;e.emitter.on("message",n=>{r++,s+=n.length;const i={messages:r,chars:s};e.emitter.emit("stats",i),n.includes(t)&&e.emitter.emit("keyword",{keyword:t,at:s})}),e.emitter.on("connecting",()=>{r=0,s=0,e.emitter.emit("stats",{messages:r,chars:s})})}}},exports.throttlePlugin=d,exports.webFetchTransport=s;
|