@laravel/stream-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Laravel Stream for React
2
+
3
+ <p align="left">
4
+ <a href="https://github.com/laravel/stream/actions/workflows/tests.yml"><img src="https://github.com/laravel/stream/actions/workflows/tests.yml/badge.svg" alt="Build Status"></a>
5
+ <a href="https://www.npmjs.com/package/@laravel/stream-react"><img src="https://img.shields.io/npm/dt/@laravel/stream-react" alt="Total Downloads"></a>
6
+ <a href="https://www.npmjs.com/package/@laravel/stream-react"><img src="https://img.shields.io/npm/v/@laravel/stream-react" alt="Latest Stable Version"></a>
7
+ <a href="https://www.npmjs.com/package/@laravel/stream-react"><img src="https://img.shields.io/npm/l/@laravel/stream-react" alt="License"></a>
8
+ </p>
9
+
10
+ Easily consume [Server-Sent Events (SSE)](https://laravel.com/docs/responses#event-streams) in your React application.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @laravel/stream-react
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ Provide your stream URL and the hook will automatically update the `message` with the concatenated response as messages are returned from your server:
21
+
22
+ ```tsx
23
+ import { useStream } from "@laravel/stream-react";
24
+
25
+ function App() {
26
+ const { message } = useStream("/stream");
27
+
28
+ return <div>{message}</div>;
29
+ }
30
+ ```
31
+
32
+ You also have access to the array of message parts:
33
+
34
+ ```tsx
35
+ import { useStream } from "@laravel/stream-react";
36
+
37
+ function App() {
38
+ const { messageParts } = useStream("/stream");
39
+
40
+ return (
41
+ <ul>
42
+ {messageParts.forEach((message) => (
43
+ <li>{message}</li>
44
+ ))}
45
+ </ul>
46
+ );
47
+ }
48
+ ```
49
+
50
+ The second parameter is options object, all properties are optional (defaults are shown here):
51
+
52
+ ```tsx
53
+ import { useStream } from "@laravel/stream-react";
54
+
55
+ function App() {
56
+ const { message } = useStream("/stream", {
57
+ event: "update",
58
+ endSignal: "</stream>",
59
+ glue: " ",
60
+ onMessage: (message) => {
61
+ //
62
+ },
63
+ onError: (error) => {
64
+ //
65
+ },
66
+ onComplete: () => {
67
+ //
68
+ },
69
+ });
70
+
71
+ return <div>{message}</div>;
72
+ }
73
+ ```
74
+
75
+ ## License
76
+
77
+ Laravel Stream is open-sourced software licensed under the [MIT license](LICENSE.md).
@@ -0,0 +1,29 @@
1
+ declare type Options = {
2
+ eventName?: string;
3
+ endSignal?: string;
4
+ glue?: string;
5
+ onMessage?: (event: MessageEvent) => void;
6
+ onComplete?: () => void;
7
+ onError?: (error: Event) => void;
8
+ };
9
+
10
+ declare type StreamResult = {
11
+ message: string;
12
+ messageParts: string[];
13
+ close: (resetMessage?: boolean) => void;
14
+ clearMessage: () => void;
15
+ };
16
+
17
+ /**
18
+ * Hook for handling server-sent event (SSE) streams
19
+ *
20
+ * @param url - The URL to connect to for the EventSource
21
+ * @param options - Options for the stream
22
+ *
23
+ * @link https://laravel.com/docs/responses#event-streams
24
+ *
25
+ * @returns StreamResult object containing the accumulated response, close, and reset functions
26
+ */
27
+ export declare const useStream: (url: string, { eventName, endSignal, glue, onMessage, onComplete, onError, }?: Options) => StreamResult;
28
+
29
+ export { }
@@ -0,0 +1,38 @@
1
+ import { useRef as p, useState as L, useCallback as c, useEffect as C } from "react";
2
+ const l = "data: ", j = (d, {
3
+ eventName: t = "update",
4
+ endSignal: i = "</stream>",
5
+ glue: f = " ",
6
+ onMessage: P = () => null,
7
+ onComplete: R = () => null,
8
+ onError: S = () => null
9
+ } = {}) => {
10
+ const r = p(null), s = p([]), [b, g] = L(""), [x, E] = L([]), n = c(() => {
11
+ s.current = [], g(""), E([]);
12
+ }, []), u = c(
13
+ (e) => {
14
+ if ([i, `${l}${i}`].includes(e.data)) {
15
+ a(), R();
16
+ return;
17
+ }
18
+ s.current.push(
19
+ e.data.startsWith(l) ? e.data.substring(l.length) : e.data
20
+ ), g(s.current.join(f)), E(s.current), P(e);
21
+ },
22
+ [t, f]
23
+ ), o = c((e) => {
24
+ S(e), a();
25
+ }, []), a = c((e = !1) => {
26
+ var m, h, M;
27
+ (m = r.current) == null || m.removeEventListener(t, u), (h = r.current) == null || h.removeEventListener("error", o), (M = r.current) == null || M.close(), r.current = null, e && n();
28
+ }, []);
29
+ return C(() => (n(), r.current = new EventSource(d), r.current.addEventListener(t, u), r.current.addEventListener("error", o), a), [d, t, u, o, n]), {
30
+ message: b,
31
+ messageParts: x,
32
+ close: a,
33
+ clearMessage: n
34
+ };
35
+ };
36
+ export {
37
+ j as useStream
38
+ };
@@ -0,0 +1 @@
1
+ (function(t,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],e):(t=typeof globalThis<"u"?globalThis:t||self,e(t.LaravelStreamReact={},t.React))})(this,function(t,e){"use strict";const c="data: ",E=(d,{eventName:n="update",endSignal:f="</stream>",glue:g=" ",onMessage:M=()=>null,onComplete:R=()=>null,onError:C=()=>null}={})=>{const r=e.useRef(null),u=e.useRef([]),[L,m]=e.useState(""),[P,p]=e.useState([]),a=e.useCallback(()=>{u.current=[],m(""),p([])},[]),l=e.useCallback(s=>{if([f,`${c}${f}`].includes(s.data)){o(),R();return}u.current.push(s.data.startsWith(c)?s.data.substring(c.length):s.data),m(u.current.join(g)),p(u.current),M(s)},[n,g]),i=e.useCallback(s=>{C(s),o()},[]),o=e.useCallback((s=!1)=>{var h,S,b;(h=r.current)==null||h.removeEventListener(n,l),(S=r.current)==null||S.removeEventListener("error",i),(b=r.current)==null||b.close(),r.current=null,s&&a()},[]);return e.useEffect(()=>(a(),r.current=new EventSource(d),r.current.addEventListener(n,l),r.current.addEventListener("error",i),o),[d,n,l,i,a]),{message:L,messageParts:P,close:o,clearMessage:a}};t.useStream=E,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@laravel/stream-react",
3
+ "version": "0.1.0",
4
+ "description": "The Laravel useStream hook for React",
5
+ "keywords": [
6
+ "laravel",
7
+ "stream",
8
+ "use-stream",
9
+ "server-sent-events",
10
+ "sse",
11
+ "react",
12
+ "hooks"
13
+ ],
14
+ "homepage": "https://github.com/laravel/stream/tree/main/packages/react#readme",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/laravel/stream.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/laravel/stream/issues"
21
+ },
22
+ "license": "MIT",
23
+ "author": {
24
+ "name": "Taylor Otwell"
25
+ },
26
+ "type": "module",
27
+ "main": "dist/index.umd.js",
28
+ "module": "dist/index.es.js",
29
+ "types": "dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.es.js",
34
+ "require": "./dist/index.umd.js"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "devDependencies": {
41
+ "@testing-library/dom": "^10.4.0",
42
+ "@testing-library/react": "^16.3.0",
43
+ "@types/node": "^22.14.0",
44
+ "@types/react": "^19.1.0",
45
+ "@typescript-eslint/eslint-plugin": "^8.21.0",
46
+ "@typescript-eslint/parser": "^8.21.0",
47
+ "@vitejs/plugin-vue": "^5.0.0",
48
+ "eslint": "^9.0.0",
49
+ "jsdom": "^26.0.0",
50
+ "prettier": "^3.5.3",
51
+ "typescript": "^5.3.0",
52
+ "vite-plugin-dts": "^4.5.3",
53
+ "vite": "^5.1.0",
54
+ "vitest": "^3.1.1"
55
+ },
56
+ "peerDependencies": {
57
+ "react": "^18.0.0 || ^19.0.0"
58
+ },
59
+ "scripts": {
60
+ "build": "vite build",
61
+ "lint": "eslint --config eslint.config.mjs \"src/**/*.ts\"",
62
+ "prepublish": "pnpm run build",
63
+ "release": "vitest --run && git push --follow-tags && pnpm publish",
64
+ "test": "vitest",
65
+ "format": "prettier --write ."
66
+ }
67
+ }