From 46e26c2fe534d9aebc0ca1d1b3d1f0943781eee0 Mon Sep 17 00:00:00 2001 From: KATT Date: Fri, 13 Oct 2023 17:22:48 +0200 Subject: [PATCH] cool --- examples/sse/package.json | 25 ---------- examples/sse/src/index.html | 18 ------- examples/sse/src/server.ts | 91 ----------------------------------- examples/sse/src/shared.ts | 21 -------- examples/sse/tsconfig.json | 11 ----- pnpm-lock.yaml | 7 +++ src/async/createTsonAsync.ts | 3 +- src/async/deserializeAsync.ts | 16 ++---- src/async/iterableUtils.ts | 4 +- src/async/serializeAsync.ts | 9 +--- src/async/sse.test.ts | 2 +- 11 files changed, 16 insertions(+), 191 deletions(-) delete mode 100644 examples/sse/package.json delete mode 100644 examples/sse/src/index.html delete mode 100644 examples/sse/src/server.ts delete mode 100644 examples/sse/src/shared.ts delete mode 100644 examples/sse/tsconfig.json diff --git a/examples/sse/package.json b/examples/sse/package.json deleted file mode 100644 index 5179843a..00000000 --- a/examples/sse/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@examples/sse", - "version": "10.38.5", - "private": true, - "description": "An example project for tupleson", - "license": "MIT", - "module": "module", - "workspaces": [ - "client", - "server" - ], - "scripts": { - "build": "tsc", - "dev:server": "tsx watch src/server", - "dev": "run-p dev:* --print-label" - }, - "devDependencies": { - "@types/node": "^18.16.16", - "npm-run-all": "^4.1.5", - "tsx": "^3.12.7", - "tupleson": "latest", - "typescript": "^5.1.3", - "wait-port": "^1.0.1" - } -} diff --git a/examples/sse/src/index.html b/examples/sse/src/index.html deleted file mode 100644 index 88aa0c37..00000000 --- a/examples/sse/src/index.html +++ /dev/null @@ -1,18 +0,0 @@ - -

SSE test

- - See log output / inspector tools - - - diff --git a/examples/sse/src/server.ts b/examples/sse/src/server.ts deleted file mode 100644 index 15dbfd06..00000000 --- a/examples/sse/src/server.ts +++ /dev/null @@ -1,91 +0,0 @@ -import fs from "node:fs"; -import http from "node:http"; -import { createTsonSSEResponse } from "tupleson"; - -import { tsonOptions } from "./shared.js"; - -const createResponse = createTsonSSEResponse(tsonOptions); - -const randomNumber = (min: number, max: number) => - Math.floor(Math.random() * (max - min + 1) + min); - -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -/** - * This function returns the object we will be sending to the client. - */ -export function getResponseShape() { - async function* bigintGenerator() { - const iterate = new Array(10).fill(0).map((_, i) => BigInt(i)); - for (const number of iterate) { - await sleep(randomNumber(1, 400)); - yield number; - } - } - - async function* numberGenerator() { - const iterate = new Array(10).fill(0).map((_, i) => i); - for (const number of iterate) { - await sleep(randomNumber(1, 400)); - yield number; - } - } - - return { - bigints: bigintGenerator(), - foo: "bar", - numbers: numberGenerator(), - promise: new Promise((resolve) => - setTimeout(() => { - resolve(42); - }, 1), - ), - rejectedPromise: new Promise((_, reject) => - setTimeout(() => { - reject(new Error("Rejected promise")); - }, 1), - ), - }; -} - -export type ResponseShape = ReturnType; -async function handleRequest( - req: http.IncomingMessage, - res: http.ServerResponse, -) { - if (req.url?.startsWith("/sse")) { - const obj = getResponseShape(); - const response = createResponse(obj); - - // Stream the response to the client - for (const [key, value] of response.headers) { - res.setHeader(key, value); - } - - for await (const value of response.body as any) { - res.write(value); - } - - res.end(); - return; - } - - const data = fs.readFileSync(__dirname + "/index.html"); - res.write(data.toString()); - res.end(); -} - -const server = http.createServer( - (req: http.IncomingMessage, res: http.ServerResponse) => { - handleRequest(req, res).catch((err) => { - console.error(err); - res.writeHead(500, { "Content-Type": "text/plain" }); - res.end("Internal Server Error\n"); - }); - }, -); - -const port = 3000; -server.listen(port); - -console.log(`Server running at http://localhost:${port}`); diff --git a/examples/sse/src/shared.ts b/examples/sse/src/shared.ts deleted file mode 100644 index cc973f9d..00000000 --- a/examples/sse/src/shared.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - TsonAsyncOptions, - tsonAsyncIterable, - tsonBigint, - tsonPromise, -} from "tupleson"; - -/** - * Shared tupleSON options for the server and client. - */ -export const tsonOptions: TsonAsyncOptions = { - // We need to specify the types we want to allow serialization of - types: [ - // Allow serialization of promises - tsonPromise, - // Allow serialization of async iterators - tsonAsyncIterable, - // Allow serialization of bigints - tsonBigint, - ], -}; diff --git a/examples/sse/tsconfig.json b/examples/sse/tsconfig.json deleted file mode 100644 index 95c6bc3b..00000000 --- a/examples/sse/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "node", - "outDir": "dist", - "strict": true, - "target": "esnext" - }, - "include": ["src"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aca1712a..6fd40ef6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@types/eslint': specifier: ^8.44.3 version: 8.44.3 + '@types/event-source-polyfill': + specifier: ^1.0.2 + version: 1.0.2 '@typescript-eslint/eslint-plugin': specifier: ^6.7.3 version: 6.7.3(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2) @@ -1238,6 +1241,10 @@ packages: resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==} dev: true + /@types/event-source-polyfill@1.0.2: + resolution: {integrity: sha512-qE5zrFd73BRs5oSjVys6g/5GboqOMbzLRTUFPAhfULvvvbRAOXw9m4Wk+p1BtoZm4JgW7TljGGfVabBqvi3eig==} + dev: true + /@types/http-cache-semantics@4.0.2: resolution: {integrity: sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==} dev: true diff --git a/src/async/createTsonAsync.ts b/src/async/createTsonAsync.ts index c23c490c..7009ccac 100644 --- a/src/async/createTsonAsync.ts +++ b/src/async/createTsonAsync.ts @@ -6,9 +6,8 @@ import { } from "./serializeAsync.js"; /** - * @internal - * * Only used for testing - when using the async you gotta pick which one you want + * @internal */ export const createTsonAsync = (opts: TsonAsyncOptions) => ({ parseJsonStream: createTsonParseAsync(opts), diff --git a/src/async/deserializeAsync.ts b/src/async/deserializeAsync.ts index 7fb3e856..bad12800 100644 --- a/src/async/deserializeAsync.ts +++ b/src/async/deserializeAsync.ts @@ -11,17 +11,12 @@ import { } from "../sync/syncTypes.js"; import { TsonStreamInterruptedError } from "./asyncErrors.js"; import { - BrandSerialized, TsonAsyncIndex, TsonAsyncOptions, TsonAsyncStringifierIterable, TsonAsyncType, } from "./asyncTypes.js"; -import { - createReadableStream, - mapIterable, - readableStreamToAsyncIterable, -} from "./iterableUtils.js"; +import { createReadableStream } from "./iterableUtils.js"; import { TsonAsyncValueTuple } from "./serializeAsync.js"; type WalkFn = (value: unknown) => unknown; @@ -85,13 +80,8 @@ export function createTsonDeserializer(opts: TsonAsyncOptions) { const idx = serializedValue as TsonAsyncIndex; - let controller: ReadableStreamDefaultController = - null as unknown as ReadableStreamDefaultController; - const readable = new ReadableStream({ - start(c) { - controller = c; - }, - }); + const [readable, controller] = createReadableStream(); + // the `start` method is called "immediately when the object is constructed" // [MDN](http://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream) // so we're guaranteed that the controller is set in the cache diff --git a/src/async/iterableUtils.ts b/src/async/iterableUtils.ts index bcddad4f..a820ad66 100644 --- a/src/async/iterableUtils.ts +++ b/src/async/iterableUtils.ts @@ -1,4 +1,4 @@ -import { assert } from "../internals/assert"; +import { assert } from "../internals/assert.js"; export async function* readableStreamToAsyncIterable( stream: ReadableStream, @@ -34,7 +34,7 @@ export async function* mapIterable( } } -export function createReadableStream() { +export function createReadableStream() { let controller: ReadableStreamDefaultController = null as unknown as ReadableStreamDefaultController; const stream = new ReadableStream({ diff --git a/src/async/serializeAsync.ts b/src/async/serializeAsync.ts index 37b65257..df26b401 100644 --- a/src/async/serializeAsync.ts +++ b/src/async/serializeAsync.ts @@ -19,6 +19,7 @@ import { TsonAsyncOptions, TsonAsyncStringifier, } from "./asyncTypes.js"; +import { createReadableStream } from "./iterableUtils.js"; type WalkFn = (value: unknown) => unknown; @@ -253,13 +254,7 @@ export function createTsonSSEResponse(opts: TsonAsyncOptions) { const serialize = createAsyncTsonSerialize(opts); return (value: TValue) => { - let controller: ReadableStreamDefaultController = - null as unknown as ReadableStreamDefaultController; - const readable = new ReadableStream({ - start(c) { - controller = c; - }, - }); + const [readable, controller] = createReadableStream(); async function iterate() { const [head, iterable] = serialize(value); diff --git a/src/async/sse.test.ts b/src/async/sse.test.ts index 27785561..a380aa2a 100644 --- a/src/async/sse.test.ts +++ b/src/async/sse.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unnecessary-condition */ import { EventSourcePolyfill, NativeEventSource } from "event-source-polyfill"; import { expect, test } from "vitest"; -global.EventSource = NativeEventSource || EventSourcePolyfill; +(global as any).EventSource = NativeEventSource || EventSourcePolyfill; import { TsonAsyncOptions, tsonAsyncIterable, tsonPromise } from "../index.js"; import { createTestServer, sleep } from "../internals/testUtils.js";