Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { Low } from 'lowdb'
import { json } from 'milliparsec'
import sirv from 'sirv'

import { Data, isItem, Service } from './service.js'
import { Data, isItem, Item, Service } from './service.js'

const __dirname = dirname(fileURLToPath(import.meta.url))
const isProduction = process.env['NODE_ENV'] === 'production'

export type AppOptions = {
logger?: boolean
static?: string[]
chunk?: number
}

const eta = new Eta({
Expand Down Expand Up @@ -75,6 +76,32 @@ export function createApp(db: Low<Data>, options: AppOptions = {}) {
next?.()
})

app.get('/sse/:name', (req, res) => {
res.header('Content-Type', 'text/event-stream');
const { name = '' } = req.params

const interval = 200;

const data = service.find(name) as Item[];
if (!data.length) {
return res.sendStatus(404)
}

for (let i = 0; i < data.length; i += options.chunk!) {
setTimeout(() => {
const payload = JSON.stringify(data.slice(i, options.chunk! + i))
res.write(`data: ${payload}\n\n`);
res.flushHeaders();

if (i >= data.length) {
res.end();
}
}, i * interval);
}

return;
})

app.get('/:name/:id', (req, res, next) => {
const { name = '', id = '' } = req.params
res.locals['data'] = service.findById(name, id, req.query)
Expand Down
11 changes: 9 additions & 2 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Options:
-p, --port <port> Port (default: 3000)
-h, --host <host> Host (default: localhost)
-s, --static <dir> Static files directory (multiple allowed)
--chunk <size> Server-sent events chunk size (default: 2)
--help Show this message
--version Show version number
`)
Expand All @@ -33,6 +34,7 @@ function args(): {
port: number
host: string
static: string[]
chunk: number
} {
try {
const { values, positionals } = parseArgs({
Expand All @@ -53,6 +55,10 @@ function args(): {
multiple: true,
default: [],
},
chunk: {
type: 'string',
default: '2'
},
help: {
type: 'boolean',
},
Expand Down Expand Up @@ -100,6 +106,7 @@ function args(): {
port: parseInt(values.port as string),
host: values.host as string,
static: values.static as string[],
chunk: parseInt(values.chunk as string),
}
} catch (e) {
if ((e as NodeJS.ErrnoException).code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
Expand All @@ -112,7 +119,7 @@ function args(): {
}
}

const { file, port, host, static: staticArr } = args()
const { file, port, host, static: staticArr, chunk } = args()

if (!existsSync(file)) {
console.log(chalk.red(`File ${file} not found`))
Expand Down Expand Up @@ -140,7 +147,7 @@ const db = new Low<Data>(observer, {})
await db.read()

// Create app
const app = createApp(db, { logger: false, static: staticArr })
const app = createApp(db, { logger: false, static: staticArr, chunk })

function logRoutes(data: Data) {
console.log(chalk.bold('Endpoints:'))
Expand Down