Skip to content

Commit

Permalink
chore: keep repo up to date (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelangeloio authored Nov 12, 2023
1 parent cdb025c commit c4e535c
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 344 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:

strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [16.x, 18.x, 20.x]

steps:
- uses: actions/checkout@v3
Expand Down
52 changes: 0 additions & 52 deletions .vscode/launch.json

This file was deleted.

11 changes: 7 additions & 4 deletions examples/next-app/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import dynamic from 'next/dynamic'
import Image from 'next/image'
import { StreamClient } from './StreamClient'

const DynamicStreamClient = dynamic(() => import('./streamClient'), {
ssr: false,
})

export default function Home() {
return (
Expand All @@ -16,12 +20,11 @@ export default function Home() {
target="_blank"
rel="noopener noreferrer"
>
By{' '}
Michael Angelo Rivera
By Michael Angelo Rivera
</a>
</div>
</div>
<StreamClient></StreamClient>
<DynamicStreamClient></DynamicStreamClient>
<div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
<Image
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
Expand Down
79 changes: 28 additions & 51 deletions examples/next-app/app/stream/route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { NextResponse } from 'next/server'
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { EventNotifier, getSSEWriter } from 'ts-sse'
import { rickAstleySchema } from './types'

export const dynamic = 'force-dynamic'


type SyncEvents = EventNotifier<{
update: {
data: z.infer<typeof rickAstleySchema>,
data: z.infer<typeof rickAstleySchema>
event: 'update'
}
complete: {
Expand All @@ -23,60 +22,38 @@ type SyncEvents = EventNotifier<{
}
}>

export async function GET() {
export async function GET(request: NextRequest) {
const responseStream = new TransformStream()
const writer = responseStream.writable.getWriter()
const encoder = new TextEncoder()
const syncStatusStream = async (notifier: SyncEvents) => {
notifier.update(
{
data: 'Never gonna give you up',
event: 'update'
},
{
beforeFn: (message) => {
rickAstleySchema.parse(message.data)
},
},
)
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.update(
{
data: 'Never gonna let you down',
event: 'update'
},
)
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.update(
{
data: 'Never gonna run around and desert you',
event: 'update'
let abort = false

},
)
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.update(
{
data: 'Never gonna make you cry',
event: 'update'
request.signal.onabort = () => {
abort = true
writer.close()
}

},
)
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.update(
{
data: 'Never gonna say goodbye',
event: 'update'
},
)
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.complete(
{
data: 'Never gonna tell a lie and hurt you',
event: 'update'
},
)
const beforeFn = (message: { data: string; event: 'update' }) => {
rickAstleySchema.parse(message.data)
if (abort) {
throw new Error('Abort!')
}
}

const messages = [
'Never gonna give you up',
'Never gonna let you down',
'Never gonna run around and desert you',
'Never gonna make you cry',
'Never gonna say goodbye',
'Never gonna tell a lie and hurt you',
'fin',
]
const syncStatusStream = async (notifier: SyncEvents) => {
for (const message of messages) {
await new Promise((resolve) => setTimeout(resolve, 1000))
notifier.update({ data: message, event: 'update' }, { beforeFn })
}
}

syncStatusStream(getSSEWriter(writer, encoder))
Expand Down
89 changes: 77 additions & 12 deletions examples/next-app/app/streamClient.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,83 @@
'use client'
import { useEffect, useState } from "react"
import { z } from "zod"
import { rickAstleySchema } from "./stream/types"
import {
useEffect,
useState,
createContext,
ReactNode,
useContext,
useCallback,
} from 'react'
import { rickAstleySchema } from './stream/types'

// Create a context
const EventSourceContext = createContext<null | EventSource>(null)

export const EventSourceProvider = ({ children }: { children: ReactNode }) => {
const [eventSource, setEventSource] = useState<null | EventSource>(null)

export const StreamClient = () => {
const [lyric, setLyric] = useState<string>("")
const source = new EventSource("http://localhost:3000/stream")
useEffect(() => {
source.addEventListener('update', (event) => {
const parsed = rickAstleySchema.safeParse(event.data)
if (parsed.success) {
setLyric(parsed.data)
}
const source = new EventSource('http://localhost:3000/stream', {
withCredentials: true,
})
setEventSource(source)

return () => {
source.close()
}
}, [])

return (
<EventSourceContext.Provider value={eventSource}>
{children}
</EventSourceContext.Provider>
)
}

const StreamClient = () => {
const [lyric, setLyric] = useState<string>('')

const eventSource = useContext(EventSourceContext)
const updateLyric = useCallback((event: MessageEvent) => {
const parsed = rickAstleySchema.safeParse(event.data)
if (parsed.success) {
setLyric(parsed.data)
if (parsed.data === 'fin') {
eventSource?.close()
}
}
}, [])

useEffect(() => {
if (eventSource) {
eventSource.onerror = (error) => {
console.error('EventSource failed:', error)
}
eventSource.addEventListener('update', updateLyric)

return () => {
eventSource.removeEventListener('update', updateLyric)
}
}
}, [eventSource])

return lyric
}
}

const StreamClientComponent = () => {
const lyric = StreamClient()
return (
<div className="flex flex-col items-center justify-center w-full min-h-[50vh]">
<h1 className="text-6xl font-bold text-center">{lyric}</h1>
</div>
)
}

const StreamClientComponentWithProvider = () => {
return (
<EventSourceProvider>
<StreamClientComponent />
</EventSourceProvider>
)
}

export default StreamClientComponentWithProvider
30 changes: 15 additions & 15 deletions examples/next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-app",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"scripts": {
"dev": "next dev",
Expand All @@ -9,19 +9,19 @@
"lint": "next lint"
},
"dependencies": {
"@types/node": "20.5.9",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"autoprefixer": "10.4.15",
"eslint": "8.48.0",
"eslint-config-next": "13.4.19",
"next": "13.4.19",
"postcss": "8.4.29",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"@types/node": "^20.9.0",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"autoprefixer": "^10.4.16",
"eslint": "^8.53.0",
"eslint-config-next": "^14.0.2",
"next": "^14.0.2",
"postcss": "^8.4.31",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.3.5",
"ts-sse": "^0.0.5",
"typescript": "5.2.2",
"zod": "^3.22.2"
"typescript": "^5.2.2",
"zod": "^3.22.4"
}
}
}
Loading

0 comments on commit c4e535c

Please sign in to comment.