8,037 Matching Annotations
  1. Mar 2023
    1. ```js // FromStream component

      import { PureComponent } from 'react';

      export default class FromStream extends PureComponent { constructor(props) { super(props); this.state = { value: false }; }

      componentDidMount() { this.initStream(); }

      componentDidUpdate(prevProps) { if (prevProps.stream !== this.props.stream) { this.initStream(); } }

      componentWillUnmount() { if (this.unSubscribe) { this.unSubscribe(); } }

      initStream() { if (this.unSubscribe) { this.unSubscribe(); this.unSubscribe = null; }

      if (this.props.stream) {
        const onValue = (value) => {
          this.setState(() => ({ value: map(value) }));
        };
      
        this.props.stream.onValue(onValue);
        this.unSubscribe = () => stream.offValue(onValue);
      }
      

      }

      render() { return this.props.children(this.state && this.state.value); } } ```

      ```js // Date/Time import React from 'react'; import Kefir from 'kefir'; import FromStream from './FromStream';

      const dateStream = Kefir.interval(1000).map(() => new Date().toString());

      export default () => ( <FromStream stream={dateStream}> {(dateString) => dateString} </FromStream> ); ```

      ```js // Scroll import React from 'react'; import Kefir from 'kefir'; import FromStream from './FromStream';

      const scrolledPercentStream = Kefir.fromEvents(document, 'scroll').map((e) => { const scrollY = window.document.pageYOffset; const scrollHeight = e.target.body.scrollHeight; return scrollY / (scrollHeight - windiw.innerHeight) * 100; });

      export default () => ( <FromStream stream={scrolledPercentStream}> {(percent) => ( <div className="bar" style={{ top: <code>${percent}% }}></div> )} </FromStream> ); ```

    1. ```js import { useState, useEffect } from 'react';

      interface StreamState { data: Uint8Array | null; error: Error | null; controller: AbortController; }

      const useAbortableStreamFetch = (url: string, options?: RequestInit): { data: Uint8Array | null, error: Error | null, abort: () => void, } => {

      const [state, setState] = useState<StreamState>({ data: null, error: null, controller: new AbortController(), });

      useEffect(() => { (async () => { try { const resp = await fetch(url, { ...options, signal: state.controller.signal, }); if (!resp.ok || !resp.body) { throw resp.statusText; }

          const reader = resp.body.getReader();
          while (true) {
            const { value, done } = await reader.read();
            if (done) {
              break;
            }
      
            setState(prevState => ({ ...prevState, ...{ data: value } }));
          }
        } catch (err) {
          if (err.name !== 'AbortError') {
            setState(prevState => ({ ...prevState, ...{ error: err } }));
          }
        }
      })();
      
      return () => state.controller.abort();
      

      }, [url, options]);

      return { data: state.data, error: state.error, abort: () => state.controller && state.controller.abort(), }; };

      export default useAbortableStreamFetch; ```

    1. Send the 304 Not Modified response

      ```js import etag from "etag"; import { renderToString } from "react-dom/server"; import type { EntryContext, HandleDataRequestFunction } from "remix"; import { RemixServer } from "remix";

      export default function handleRequest( request: Request, status: number, headers: Headers, remixContext: EntryContext ) { let markup = renderToString( <RemixServer context={remixContext} url={request.url} /> );

      headers.set("Content-Type", "text/html"); headers.set("ETag", etag(markup));

      // check if the If-None-Match header matches the ETag if (request.headers.get("If-None-Match") === headers.get("ETag")) { // and send an empty Response with status 304 and the headers. return new Response("", { status: 304, headers }); }

      return new Response("<!DOCTYPE html>" + markup, { status, headers }); }

      export let handleDataRequest: HandleDataRequestFunction = async ( response: Response, { request } ) => { let body = await response.text();

      if (request.method.toLowerCase() === "get") { response.headers.set("etag", etag(body)); // As with document requests, check the If-None-Match header // and compare it with the Etag, if they match, send the empty 304 Response if (request.headers.get("If-None-Match") === response.headers.get("ETag")) { return new Response("", { status: 304, headers: response.headers }); } }

      return response; }; ```

    2. All Together

      ```js import etag from "etag"; import { renderToString } from "react-dom/server"; import type { EntryContext, HandleDataRequestFunction } from "remix"; import { RemixServer } from "remix";

      export default function handleRequest( request: Request, status: number, headers: Headers, remixContext: EntryContext ) { let markup = renderToString( <RemixServer context={remixContext} url={request.url} /> );

      headers.set("Content-Type", "text/html"); headers.set("ETag", etag(markup));

      return new Response("<!DOCTYPE html>" + markup, { status, headers }); }

      export let handleDataRequest: HandleDataRequestFunction = async ( response: Response ) => { let body = await response.text(); response.headers.set("etag", etag(body)); return response; }; ```

    3. Using ETags for document requests

      ```js import etag from "etag"; import { renderToString } from "react-dom/server"; import type { EntryContext } from "remix"; import { RemixServer } from "remix";

      export default function handleRequest( request: Request, status: number, headers: Headers, remixContext: EntryContext ) { let markup = renderToString( <RemixServer context={remixContext} url={request.url} /> );

      headers.set("Content-Type", "text/html"); // add the Etag header using the markup as value headers.set("ETag", etag(markup));

      return new Response("<!DOCTYPE html>" + markup, { status, headers }); } ```

    4. Using ETags for data requests

      ```js import etag from "etag"; import type { HandleDataRequestFunction } from "remix";

      export let handleDataRequest: HandleDataRequestFunction = async ( response: Response, { request } ) => { let body = await response.text(); // parse the response body as text

      // only add the ETag for GET requests if (request.method.toLowerCase() === "get") { response.headers.set("etag", etag(body)); // and use it to create the ETag }

      return response; // return the response }; ```

    1. ```js import { renderToString } from "react-dom/server"; import { RemixServer } from "remix"; import type { EntryContext } from "remix"; import { etag } from 'remix-etag';

      export default function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) { const markup = renderToString( <RemixServer context={remixContext} url={request.url} /> );

      responseHeaders.set("Content-Type", "text/html");

      const response = new Response("<!DOCTYPE html>" + markup, { status: responseStatusCode, headers: responseHeaders, }); return etag({ request, response }); } ```

    1. ```sparql PREFIX wd: http://www.wikidata.org/entity/ PREFIX gist: https://ontologies.semanticarts.com/gist/ PREFIX dcterms: http://purl.org/dc/terms/

      SELECT DISTINCT ?commitTitle ?commitTime ?filename ?textLine WHERE {

      ?commit a wd:Q20058545 ; # it's a commit gist:hasPart ?part ; dcterms:subject ?commitSubject ; gist:atDateTime ?commitTime .

      ?commitSubject dcterms:title ?commitTitle .

      ?part gist:produces ?contiguousLines .

      ?contiguousLines gist:occursIn ?file ; http://example.com/containedTextContainer ?textContainer .

      ?file gist:name ?filename . ?textContainer ?line ?textLine .

      FILTER(contains(?textLine,"music")) } ```

  2. developer.mozilla.org developer.mozilla.org
    1. ```http HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked Trailer: Expires

      7\r\n Mozilla\r\n 9\r\n Developer\r\n 7\r\n Network\r\n 0\r\n Expires: Wed, 21 Oct 2015 07:28:00 GMT\r\n \r\n ```

    1. ```js import { renderToReadableStream } from 'react-dom/server'; import type { EntryContext } from '@remix-run/cloudflare'; import { RemixServer } from '@remix-run/react'; import { renderHeadToString } from 'remix-island'; import { Head } from './root';

      const readableString = (value: string) => { const te = new TextEncoder(); return new ReadableStream({ start(controller) { controller.enqueue(te.encode(value)); controller.close(); }, }); };

      export default async function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext, ) { const { readable, writable } = new TransformStream(); const head = readableString( <!DOCTYPE html><html><head>${renderHeadToString({ request, remixContext, Head, })}</head><body><div id="root">, ); const end = readableString(</div></body></html>);

      const body = await renderToReadableStream( <RemixServer context={remixContext} url={request.url} />, );

      Promise.resolve() .then(() => head.pipeTo(writable, { preventClose: true })) .then(() => body.pipeTo(writable, { preventClose: true })) .then(() => end.pipeTo(writable));

      responseHeaders.set('Content-Type', 'text/html');

      return new Response(readable, { status: responseStatusCode, headers: responseHeaders, }); } ```

    1. ```js import React, { Component } from 'react'; import './style.css'; import ndjsonStream from 'can-ndjson-stream';

      class App extends Component { constructor(props) { super(props);

      this.state = {
        todos: []
      };
      

      }

      componentDidMount(){ fetch('http://localhost:5000/api/10', { method: 'get' }).then(data => { return ndjsonStream(data.body); }).then((todoStream) => { const streamReader = todoStream.getReader(); const read = result => { if (result.done) return;

          this.setState({ 
            todos: this.state.todos.concat([result.value.user])
          });
      
          streamReader.read().then(read);
        };
      
        streamReader.read().then(read); 
      }).catch(err => {
        console.error(err)
      });
      

      }

      render() { return ( <div className="App">

      React + NDJSON Stream Demo

        {this.state.todos.map((todo, i) =>
      • {todo}
      • )}
      </div> ); } }

      export default App; ```

    1. Streaming across worker threads

      ```js import { ReadableStream } from 'node:stream/web'; import { Worker } from 'node:worker_threads';

      const readable = new ReadableStream(getSomeSource());

      const worker = new Worker('/path/to/worker.js', { workerData: readable, transferList: [readable], }); ```

      ```js const { workerData: stream } = require('worker_threads');

      const reader = stream.getReader(); reader.read().then(console.log); ```

    2. Consuming web streams

      ```js import { arrayBuffer, blob, buffer, json, text, } from 'node:stream/consumers';

      const data1 = await arrayBuffer(getReadableStreamSomehow());

      const data2 = await blob(getReadableStreamSomehow());

      const data3 = await buffer(getReadableStreamSomehow());

      const data4 = await json(getReadableStreamSomehow());

      const data5 = await text(getReadableStreamSomehow()); ```

    3. Adapting to the Node.js Streams API

      ```js /* * For instance, given a ReadableStream object, the stream.Readable.fromWeb() method * will create an return a Node.js stream.Readable object that can be used to consume * the ReadableStream's data: / import { Readable } from 'node:stream';

      const readable = new ReadableStream(getSomeSource());

      const nodeReadable = Readable.fromWeb(readable);

      nodeReadable.on('data', console.log); ```

      ```js /* * The adaptation can also work the other way -- starting with a Node.js * stream.Readable and acquiring a web streams ReadableStream: / import { Readable } from 'node:stream';

      const readable = new Readable({ read(size) { reader.push(Buffer.from('hello')); } });

      const readableStream = Readable.toWeb(readable);

      await readableStream.read();

      ```

    1. One option is to use the serialize-javascript NPM module to escape the rendered JSON.

      html { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }

    2. This is risky because JSON.stringify() will blindly turn any data you give it into a string (so long as it is valid JSON) which will be rendered in the page. If { data } has fields that un-trusted users can edit like usernames or bios, they can inject something like this:

      json { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" }

    3. Sometimes when we render initial state, we dangerously generate a document variable from a JSON string. Vulnerable code looks like this:

      ```html

      <script>window.__STATE__ = ${JSON.stringify({ data })}</script>

      ```

    4. Server-side rendering attacker-controlled initial state
    1. To pass along the state, the template attaches state to window.__STATE__ inside a <script> tag.Now you can read state on the client side by accessing window.__STATE__.
    1. Async iteration of a stream using for await...ofThis example shows how you can process the fetch() response using a for await...of loop to iterate through the arriving chunks.

      ```js const response = await fetch("https://www.example.org"); let total = 0;

      // Iterate response.body (a ReadableStream) asynchronously for await (const chunk of response.body) { // Do something with each chunk // Here we just accumulate the size of the response. total += chunk.length; }

      // Do something with the total console.log(total); ```

    1. The body read-only property of the Response interface is a ReadableStream of the body contents.
    1. js match (res) { if (isEmpty(res)) { … } when ({ pages, data }) if (pages > 1) { … } when ({ pages, data }) if (pages === 1) { … } else { … } }


      js match (arithmeticStr) { when (/(?<left>\d+) \+ (?<right>\d+)/) as ({ groups: { left, right } }) { process(left, right); } when (/(?<left>\d+) \+ (?<right>\d+)/) { process(left, right); } // maybe? else { ... } }


      ```js class Name { static Symbol.matcher { const pieces = matchable.split(' '); if (pieces.length === 2) { return { matched: true, value: pieces }; } } }

      match ('Tab Atkins-Bittner') { when (^Name with [first, last]) if (last.includes('-')) { … } when (^Name with [first, last]) { … } else { ... } } ```


      js const res = await fetch(jsonService) match (res) { when ({ status: 200, headers: { 'Content-Length': s } }) { console.log(`size is ${s}`); } when ({ status: 404 }) { console.log('JSON not found'); } when ({ status }) if (status >= 400) { throw new RequestError(res); } };


      ```js function todoApp(state = initialState, action) { return match (action) { when ({ type: 'set-visibility-filter', payload: visFilter }) { ({ ...state, visFilter }); } when ({ type: 'add-todo', payload: text }) { ({ ...state, todos: [...state.todos, { text, completed: false }] }); } when ({ type: 'toggle-todo', payload: index }) { const newTodos = state.todos.map((todo, i) => { return i !== index ? todo : { ...todo, completed: !todo.completed }; });

        ({
          ...state,
          todos: newTodos,
        });
      }
      else { state } // ignore unknown actions
      

      } } ```


      jsx <Fetch url={API_URL}> {props => match (props) { when ({ loading }) { <Loading />; } when ({ error }) { <Error error={error} />; } when ({ data }) { <Page data={data} />; } }} </Fetch>

    1. You'll notice that for the app/routes/jokes/$jokeId.tsx route in addition to Cache-Control we've also set Vary header to Cookie. This is because we're returning something that's specific to the user who is logged in. So we want the cache to associated to that particular Cookie value and not shared with different users, so the browser and CDN will not deliver the cached value if the cookie is different from the cached response's cookie.
    1. ```js import parseCacheControl from "parse-cache-control";

      export function headers({ loaderHeaders, parentHeaders, }: { loaderHeaders: Headers; parentHeaders: Headers; }) { const loaderCache = parseCacheControl( loaderHeaders.get("Cache-Control") ); const parentCache = parseCacheControl( parentHeaders.get("Cache-Control") );

      // take the most conservative between the parent and loader, otherwise // we'll be too aggressive for one of them. const maxAge = Math.min( loaderCache["max-age"], parentCache["max-age"] );

      return { "Cache-Control": max-age=${maxAge}, }; } ```


      ```js import { renderToString } from "react-dom/server"; import { RemixServer } from "@remix-run/react"; import type { EntryContext } from "@remix-run/node"; // or cloudflare/deno

      export default function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) { const markup = renderToString( <RemixServer context={remixContext} url={request.url} /> );

      responseHeaders.set("Content-Type", "text/html"); responseHeaders.set("X-Powered-By", "Hugs");

      return new Response("<!DOCTYPE html>" + markup, { status: responseStatusCode, headers: responseHeaders, }); } ```

  3. Feb 2023
    1. ```js import type { EntryContext } from "@remix-run/cloudflare"; import { RemixServer } from "@remix-run/react"; import isbot from "isbot"; import { renderToReadableStream } from "react-dom/server";

      const ABORT_DELAY = 5000;

      const handleRequest = async ( request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext ) => { let didError = false;

      const stream = await renderToReadableStream( <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, { onError: (error: unknown) => { didError = true; console.error(error);

          // You can also log crash/error report
        },
        signal: AbortSignal.timeout(ABORT_DELAY),
      }
      

      );

      if (isbot(request.headers.get("user-agent"))) { await stream.allReady; }

      responseHeaders.set("Content-Type", "text/html"); return new Response(stream, { headers: responseHeaders, status: didError ? 500 : responseStatusCode, }); };

      export default handleRequest; ```