0.0.8
This commit is contained in:
parent
8fc226ce09
commit
d1caf3fbf4
|
|
@ -7,7 +7,7 @@
|
|||
"dependencies": {
|
||||
"@because/forge": "^0.0.1",
|
||||
"@because/hype": "^0.0.2",
|
||||
"@because/toes": "^0.0.6",
|
||||
"@because/toes": "^0.0.7",
|
||||
"croner": "^9.1.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
"@because/hype": ["@because/hype@0.0.2", "https://npm.nose.space/@because/hype/-/hype-0.0.2.tgz", { "dependencies": { "hono": "^4.10.4", "kleur": "^4.1.5" }, "peerDependencies": { "typescript": "^5" } }, "sha512-fdKeII6USGC1loVVj+tPz086cKz+Bm+XozNee3NOnK4VP+q4yNPP2Fq1Yujw5xeDYE+ZvJn40gKwlngRvmX2hA=="],
|
||||
|
||||
"@because/toes": ["@because/toes@0.0.6", "https://npm.nose.space/@because/toes/-/toes-0.0.6.tgz", { "dependencies": { "@because/forge": "^0.0.1", "@because/hype": "^0.0.2", "commander": "^14.0.2", "diff": "^8.0.3", "kleur": "^4.1.5" }, "peerDependencies": { "typescript": "^5.9.2" }, "bin": { "toes": "src/cli/index.ts" } }, "sha512-37x3E1qtG6yhF6Cm9DtevCb02t3KbPTBvG/ysonVgA8RGQqV/vagOF4/CNLiVXioEweM5RWtrqOtYtTMqOjufA=="],
|
||||
"@because/sneaker": ["@because/sneaker@0.0.1", "https://npm.nose.space/@because/sneaker/-/sneaker-0.0.1.tgz", { "dependencies": { "hono": "^4.9.8", "unique-names-generator": "^4.7.1" }, "peerDependencies": { "typescript": "^5" } }, "sha512-rN9hc13ofap+7SvfShJkTJQYBcViCiElyfb8FBMzP1SKIe8B71csZeLh+Ujye/5538ojWfM/5hRRPJ+Aa/0A+g=="],
|
||||
|
||||
"@because/toes": ["@because/toes@0.0.7", "https://npm.nose.space/@because/toes/-/toes-0.0.7.tgz", { "dependencies": { "@because/forge": "^0.0.1", "@because/hype": "^0.0.2", "@because/sneaker": "^0.0.1", "commander": "^14.0.3", "diff": "^8.0.3", "kleur": "^4.1.5" }, "peerDependencies": { "typescript": "^5.9.3" }, "bin": { "toes": "src/cli/index.ts" } }, "sha512-TZJvJIZ1qDvsixfej5GG6huwnTTKIFuG7GQ+YaOursw0f5wCgrAVQ/QhYzzszNdQsGJhErGcpyDXf8I/lCQxAw=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.8", "https://npm.nose.space/@types/bun/-/bun-1.3.8.tgz", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
|
||||
|
||||
|
|
@ -41,5 +43,7 @@
|
|||
"typescript": ["typescript@5.9.3", "https://npm.nose.space/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.16.0", "https://npm.nose.space/undici-types/-/undici-types-7.16.0.tgz", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
|
||||
"unique-names-generator": ["unique-names-generator@4.7.1", "https://npm.nose.space/unique-names-generator/-/unique-names-generator-4.7.1.tgz", {}, "sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow=="],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@because/toes",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8",
|
||||
"description": "personal web appliance - turn it on and forget about the cloud",
|
||||
"module": "src/index.ts",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -11,32 +11,59 @@ interface Listener {
|
|||
|
||||
const _listeners = new Set<Listener>()
|
||||
|
||||
let _es: EventSource | undefined
|
||||
let _abort: AbortController | undefined
|
||||
let _connected = false
|
||||
|
||||
function ensureConnection() {
|
||||
if (_es && _es.readyState !== EventSource.CLOSED) return
|
||||
if (_es) _es.close()
|
||||
if (_connected) return
|
||||
_connected = true
|
||||
const url = `${process.env.TOES_URL}/api/events/stream`
|
||||
_es = new EventSource(url)
|
||||
_abort = new AbortController()
|
||||
|
||||
_es.onerror = () => {
|
||||
if (_es?.readyState === EventSource.CLOSED) {
|
||||
console.warn('[toes] Event stream closed, reconnecting...')
|
||||
_es = undefined
|
||||
if (_listeners.size > 0) ensureConnection()
|
||||
}
|
||||
}
|
||||
fetch(url, { signal: _abort.signal })
|
||||
.then(async (res) => {
|
||||
const reader = res.body!.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buf = ''
|
||||
|
||||
_es.onmessage = (msg) => {
|
||||
try {
|
||||
const event: ToesEvent = JSON.parse(msg.data)
|
||||
_listeners.forEach(l => {
|
||||
if (l.types.includes(event.type)) l.callback(event)
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn('[toes] Failed to parse event:', e)
|
||||
}
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
buf += decoder.decode(value, { stream: true })
|
||||
|
||||
const lines = buf.split('\n')
|
||||
buf = lines.pop()!
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ')) continue
|
||||
try {
|
||||
const event: ToesEvent = JSON.parse(line.slice(6))
|
||||
_listeners.forEach(l => {
|
||||
if (l.types.includes(event.type)) l.callback(event)
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn('[toes] Failed to parse event:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e.name === 'AbortError') return
|
||||
console.warn('[toes] Event stream error, reconnecting...', e.message)
|
||||
})
|
||||
.finally(() => {
|
||||
_connected = false
|
||||
if (_listeners.size > 0) {
|
||||
setTimeout(ensureConnection, 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
if (_abort) {
|
||||
_abort.abort()
|
||||
_abort = undefined
|
||||
}
|
||||
_connected = false
|
||||
}
|
||||
|
||||
export function on(type: ToesEventType | ToesEventType[], callback: EventCallback): () => void {
|
||||
|
|
@ -49,9 +76,6 @@ export function on(type: ToesEventType | ToesEventType[], callback: EventCallbac
|
|||
|
||||
return () => {
|
||||
_listeners.delete(listener)
|
||||
if (_listeners.size === 0 && _es) {
|
||||
_es.close()
|
||||
_es = undefined
|
||||
}
|
||||
if (_listeners.size === 0) closeConnection()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user