tempest-react-sdk 0.33.2 → 0.34.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.
Files changed (36) hide show
  1. package/README.md +3 -3
  2. package/dist/components/AIChat/AIChat.cjs +2 -0
  3. package/dist/components/AIChat/AIChat.cjs.map +1 -0
  4. package/dist/components/AIChat/AIChat.js +141 -0
  5. package/dist/components/AIChat/AIChat.js.map +1 -0
  6. package/dist/components/AIChat/AIChat.module.cjs +2 -0
  7. package/dist/components/AIChat/AIChat.module.cjs.map +1 -0
  8. package/dist/components/AIChat/AIChat.module.js +58 -0
  9. package/dist/components/AIChat/AIChat.module.js.map +1 -0
  10. package/dist/components/AIChat/AIChatComposer.cjs +2 -0
  11. package/dist/components/AIChat/AIChatComposer.cjs.map +1 -0
  12. package/dist/components/AIChat/AIChatComposer.js +87 -0
  13. package/dist/components/AIChat/AIChatComposer.js.map +1 -0
  14. package/dist/components/AIChat/AIChatTurn.cjs +3 -0
  15. package/dist/components/AIChat/AIChatTurn.cjs.map +1 -0
  16. package/dist/components/AIChat/AIChatTurn.js +217 -0
  17. package/dist/components/AIChat/AIChatTurn.js.map +1 -0
  18. package/dist/components/AIChat/ai-chat-turns.cjs +2 -0
  19. package/dist/components/AIChat/ai-chat-turns.cjs.map +1 -0
  20. package/dist/components/AIChat/ai-chat-turns.js +90 -0
  21. package/dist/components/AIChat/ai-chat-turns.js.map +1 -0
  22. package/dist/styles.css +1 -1
  23. package/dist/tempest-react-sdk.cjs +1 -1
  24. package/dist/tempest-react-sdk.d.ts +415 -9
  25. package/dist/tempest-react-sdk.js +118 -114
  26. package/dist/ws/create-web-socket.cjs +1 -1
  27. package/dist/ws/create-web-socket.cjs.map +1 -1
  28. package/dist/ws/create-web-socket.js +54 -37
  29. package/dist/ws/create-web-socket.js.map +1 -1
  30. package/dist/ws/use-web-socket.cjs +1 -1
  31. package/dist/ws/use-web-socket.cjs.map +1 -1
  32. package/dist/ws/use-web-socket.js +49 -18
  33. package/dist/ws/use-web-socket.js.map +1 -1
  34. package/package.json +1 -1
  35. package/template/src/lib/api.ts +27 -5
  36. package/template/src/stores/auth.ts +14 -0
@@ -1,35 +1,66 @@
1
1
  import { createWebSocket as e } from "./create-web-socket.js";
2
2
  import { useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
3
3
  //#region src/ws/use-web-socket.ts
4
- function a(a, o = {}) {
5
- let { enabled: s = !0, onMessage: c, ...l } = o, [u, d] = i("idle"), [f, p] = i(null), m = r(null), h = r(c);
4
+ function a(e) {
5
+ try {
6
+ return JSON.parse(e);
7
+ } catch {
8
+ return e;
9
+ }
10
+ }
11
+ function o(o, s = {}) {
12
+ let { enabled: c = !0, protocols: l, maxRetries: u, initialBackoff: d, maxBackoff: f, pingInterval: p, respondToPing: m, queueWhileClosed: h, maxQueuedMessages: g } = s, [_, v] = i("idle"), [y, b] = i(null), x = r(null), S = r(s);
6
13
  return n(() => {
7
- h.current = c;
8
- }, [c]), n(() => {
9
- if (!s || !a) {
10
- d("idle");
14
+ S.current = s;
15
+ }), n(() => {
16
+ if (!c || !o) {
17
+ v("idle");
11
18
  return;
12
19
  }
13
- let t = e(a, {
14
- ...l,
15
- onStatusChange: d,
20
+ let t = e(o, {
21
+ protocols: S.current.protocols,
22
+ maxRetries: u,
23
+ initialBackoff: d,
24
+ maxBackoff: f,
25
+ pingInterval: p,
26
+ pingPayload: S.current.pingPayload,
27
+ respondToPing: m,
28
+ pongPayload: S.current.pongPayload,
29
+ queueWhileClosed: h,
30
+ maxQueuedMessages: g,
31
+ parser: (e) => (S.current.parser ?? a)(e),
32
+ onStatusChange: v,
33
+ onOpen: (e) => S.current.onOpen?.(e),
34
+ onClose: (e) => S.current.onClose?.(e),
35
+ onError: (e) => S.current.onError?.(e),
16
36
  onMessage: (e) => {
17
- p(e), h.current?.(e);
37
+ b(e), S.current.onMessage?.(e);
18
38
  }
19
39
  });
20
- return m.current = t, () => {
21
- t.close(), m.current = null;
40
+ return x.current = t, () => {
41
+ t.close(), x.current = null;
22
42
  };
23
- }, [a, s]), {
24
- status: u,
25
- lastMessage: f,
26
- send: t((e) => m.current?.send(e) ?? !1, []),
43
+ }, [
44
+ o,
45
+ c,
46
+ Array.isArray(l) ? l.join(",") : l ?? "",
47
+ u,
48
+ d,
49
+ f,
50
+ p,
51
+ m,
52
+ h,
53
+ g
54
+ ]), {
55
+ status: _,
56
+ lastMessage: y,
57
+ send: t((e) => x.current?.send(e) ?? !1, []),
27
58
  reconnect: t(() => {
28
- m.current?.reconnect();
59
+ x.current?.reconnect();
29
60
  }, [])
30
61
  };
31
62
  }
32
63
  //#endregion
33
- export { a as useWebSocket };
64
+ export { o as useWebSocket };
34
65
 
35
66
  //# sourceMappingURL=use-web-socket.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-web-socket.js","names":[],"sources":["../../src/ws/use-web-socket.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n createWebSocket,\n type CreateWebSocketOptions,\n type WebSocketController,\n type WebSocketMessage,\n type WebSocketStatus,\n} from \"./create-web-socket\";\n\nexport interface UseWebSocketOptions<T> extends Omit<CreateWebSocketOptions<T>, \"onStatusChange\"> {\n /** When false, the socket is not opened. Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseWebSocketResult<T> {\n status: WebSocketStatus;\n /** Last decoded frame received. */\n lastMessage: WebSocketMessage<T> | null;\n /** Send a payload through the active connection. Returns false when not open. */\n send: (payload: string | Blob | BufferSource) => boolean;\n /** Force a reconnect, resetting the retry counter. */\n reconnect: () => void;\n}\n\n/**\n * React hook around {@link createWebSocket}. Manages the connection lifecycle\n * for the host component and tears it down on unmount.\n */\nexport function useWebSocket<T = unknown>(\n url: string,\n options: UseWebSocketOptions<T> = {},\n): UseWebSocketResult<T> {\n const { enabled = true, onMessage, ...rest } = options;\n const [status, setStatus] = useState<WebSocketStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<WebSocketMessage<T> | null>(null);\n const controllerRef = useRef<WebSocketController | null>(null);\n\n const onMessageRef = useRef(onMessage);\n useEffect(() => {\n onMessageRef.current = onMessage;\n }, [onMessage]);\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createWebSocket<T>(url, {\n ...rest,\n onStatusChange: setStatus,\n onMessage: (message) => {\n setLastMessage(message);\n onMessageRef.current?.(message);\n },\n });\n controllerRef.current = controller;\n\n return () => {\n controller.close();\n controllerRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, enabled]);\n\n const send = useCallback((payload: string | Blob | BufferSource): boolean => {\n return controllerRef.current?.send(payload) ?? false;\n }, []);\n\n const reconnect = useCallback((): void => {\n controllerRef.current?.reconnect();\n }, []);\n\n return { status, lastMessage, send, reconnect };\n}\n"],"mappings":";;;AA4BA,SAAgB,EACZ,GACA,IAAkC,CAAC,GACd;CACrB,IAAM,EAAE,aAAU,IAAM,cAAW,GAAG,MAAS,GACzC,CAAC,GAAQ,KAAa,EAA0B,MAAM,GACtD,CAAC,GAAa,KAAkB,EAAqC,IAAI,GACzE,IAAgB,EAAmC,IAAI,GAEvD,IAAe,EAAO,CAAS;CAoCrC,OAnCA,QAAgB;EACZ,EAAa,UAAU;CAC3B,GAAG,CAAC,CAAS,CAAC,GAEd,QAAgB;EACZ,IAAI,CAAC,KAAW,CAAC,GAAK;GAClB,EAAU,MAAM;GAChB;EACJ;EAEA,IAAM,IAAa,EAAmB,GAAK;GACvC,GAAG;GACH,gBAAgB;GAChB,YAAY,MAAY;IAEpB,AADA,EAAe,CAAO,GACtB,EAAa,UAAU,CAAO;GAClC;EACJ,CAAC;EAGD,OAFA,EAAc,UAAU,SAEX;GAET,AADA,EAAW,MAAM,GACjB,EAAc,UAAU;EAC5B;CAEJ,GAAG,CAAC,GAAK,CAAO,CAAC,GAUV;EAAE;EAAQ;EAAa,MARjB,GAAa,MACf,EAAc,SAAS,KAAK,CAAO,KAAK,IAChD,CAAC,CAM0B;EAAM,WAJlB,QAAwB;GACtC,EAAc,SAAS,UAAU;EACrC,GAAG,CAAC,CAEgC;CAAU;AAClD"}
1
+ {"version":3,"file":"use-web-socket.js","names":[],"sources":["../../src/ws/use-web-socket.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n createWebSocket,\n type CreateWebSocketOptions,\n type WebSocketController,\n type WebSocketMessage,\n type WebSocketStatus,\n} from \"./create-web-socket\";\n\nexport interface UseWebSocketOptions<T> extends Omit<CreateWebSocketOptions<T>, \"onStatusChange\"> {\n /** When false, the socket is not opened. Default: true. */\n enabled?: boolean;\n}\n\nexport interface UseWebSocketResult<T> {\n status: WebSocketStatus;\n /**\n * Last decoded frame received.\n *\n * A snapshot, not a stream: two frames arriving in the same tick collapse\n * into a single render and only the later one is ever visible. One server\n * action often emits several frames in a row, so anything that must see\n * every message has to use `onMessage`, which fires once per frame. Read\n * `lastMessage` for \"what is the current state\" rendering only.\n */\n lastMessage: WebSocketMessage<T> | null;\n /** Send a payload through the active connection. Returns false when not open. */\n send: (payload: string | Blob | BufferSource) => boolean;\n /** Force a reconnect, resetting the retry counter. */\n reconnect: () => void;\n}\n\n/** Mirror of `createWebSocket`'s default parser: JSON, raw string on failure. */\nfunction defaultParse<T>(raw: string): T {\n try {\n return JSON.parse(raw) as T;\n } catch {\n return raw as unknown as T;\n }\n}\n\n/**\n * React hook around {@link createWebSocket}. Manages the connection lifecycle\n * for the host component and tears it down on unmount.\n *\n * Every callback is read through a ref, so `onOpen` / `onMessage` / `onClose` /\n * `onError` always run the latest closure — an inline arrow function is fine\n * and never reopens the socket. Connection-shaping options (`protocols`,\n * `maxRetries`, `initialBackoff`, `maxBackoff`, `pingInterval`,\n * `queueWhileClosed`) are baked into the connection, so changing one reopens\n * it with the new value rather than being silently ignored.\n *\n * @param url - Full ws:// or wss:// URL.\n * @param options - Connection configuration and callbacks.\n * @returns Status, last frame, and the `send` / `reconnect` controls.\n */\nexport function useWebSocket<T = unknown>(\n url: string,\n options: UseWebSocketOptions<T> = {},\n): UseWebSocketResult<T> {\n const {\n enabled = true,\n protocols,\n maxRetries,\n initialBackoff,\n maxBackoff,\n pingInterval,\n respondToPing,\n queueWhileClosed,\n maxQueuedMessages,\n } = options;\n const [status, setStatus] = useState<WebSocketStatus>(\"idle\");\n const [lastMessage, setLastMessage] = useState<WebSocketMessage<T> | null>(null);\n const controllerRef = useRef<WebSocketController | null>(null);\n\n const optionsRef = useRef(options);\n useEffect(() => {\n optionsRef.current = options;\n });\n\n const protocolsKey = Array.isArray(protocols) ? protocols.join(\",\") : (protocols ?? \"\");\n\n useEffect(() => {\n if (!enabled || !url) {\n setStatus(\"idle\");\n return;\n }\n\n const controller = createWebSocket<T>(url, {\n protocols: optionsRef.current.protocols,\n maxRetries,\n initialBackoff,\n maxBackoff,\n pingInterval,\n pingPayload: optionsRef.current.pingPayload,\n respondToPing,\n pongPayload: optionsRef.current.pongPayload,\n queueWhileClosed,\n maxQueuedMessages,\n parser: (raw) => (optionsRef.current.parser ?? defaultParse<T>)(raw),\n onStatusChange: setStatus,\n onOpen: (event) => optionsRef.current.onOpen?.(event),\n onClose: (event) => optionsRef.current.onClose?.(event),\n onError: (event) => optionsRef.current.onError?.(event),\n onMessage: (message) => {\n setLastMessage(message);\n optionsRef.current.onMessage?.(message);\n },\n });\n controllerRef.current = controller;\n\n return () => {\n controller.close();\n controllerRef.current = null;\n };\n }, [\n url,\n enabled,\n protocolsKey,\n maxRetries,\n initialBackoff,\n maxBackoff,\n pingInterval,\n respondToPing,\n queueWhileClosed,\n maxQueuedMessages,\n ]);\n\n const send = useCallback((payload: string | Blob | BufferSource): boolean => {\n return controllerRef.current?.send(payload) ?? false;\n }, []);\n\n const reconnect = useCallback((): void => {\n controllerRef.current?.reconnect();\n }, []);\n\n return { status, lastMessage, send, reconnect };\n}\n"],"mappings":";;;AAiCA,SAAS,EAAgB,GAAgB;CACrC,IAAI;EACA,OAAO,KAAK,MAAM,CAAG;CACzB,QAAQ;EACJ,OAAO;CACX;AACJ;AAiBA,SAAgB,EACZ,GACA,IAAkC,CAAC,GACd;CACrB,IAAM,EACF,aAAU,IACV,cACA,eACA,mBACA,eACA,iBACA,kBACA,qBACA,yBACA,GACE,CAAC,GAAQ,KAAa,EAA0B,MAAM,GACtD,CAAC,GAAa,KAAkB,EAAqC,IAAI,GACzE,IAAgB,EAAmC,IAAI,GAEvD,IAAa,EAAO,CAAO;CA6DjC,OA5DA,QAAgB;EACZ,EAAW,UAAU;CACzB,CAAC,GAID,QAAgB;EACZ,IAAI,CAAC,KAAW,CAAC,GAAK;GAClB,EAAU,MAAM;GAChB;EACJ;EAEA,IAAM,IAAa,EAAmB,GAAK;GACvC,WAAW,EAAW,QAAQ;GAC9B;GACA;GACA;GACA;GACA,aAAa,EAAW,QAAQ;GAChC;GACA,aAAa,EAAW,QAAQ;GAChC;GACA;GACA,SAAS,OAAS,EAAW,QAAQ,UAAU,EAAA,CAAiB,CAAG;GACnE,gBAAgB;GAChB,SAAS,MAAU,EAAW,QAAQ,SAAS,CAAK;GACpD,UAAU,MAAU,EAAW,QAAQ,UAAU,CAAK;GACtD,UAAU,MAAU,EAAW,QAAQ,UAAU,CAAK;GACtD,YAAY,MAAY;IAEpB,AADA,EAAe,CAAO,GACtB,EAAW,QAAQ,YAAY,CAAO;GAC1C;EACJ,CAAC;EAGD,OAFA,EAAc,UAAU,SAEX;GAET,AADA,EAAW,MAAM,GACjB,EAAc,UAAU;EAC5B;CACJ,GAAG;EACC;EACA;EArCiB,MAAM,QAAQ,CAAS,IAAI,EAAU,KAAK,GAAG,IAAK,KAAa;EAuChF;EACA;EACA;EACA;EACA;EACA;EACA;CACJ,CAAC,GAUM;EAAE;EAAQ;EAAa,MARjB,GAAa,MACf,EAAc,SAAS,KAAK,CAAO,KAAK,IAChD,CAAC,CAM0B;EAAM,WAJlB,QAAwB;GACtC,EAAc,SAAS,UAAU;EACrC,GAAG,CAAC,CAEgC;CAAU;AAClD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.33.2",
3
+ "version": "0.34.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,15 +1,37 @@
1
1
  import { createApiClient, createQueryKeys } from "tempest-react-sdk";
2
2
 
3
- import { useAuth } from "@/stores/auth";
3
+ /** Reads the current bearer token, or null when there is no session. */
4
+ export type TokenProvider = () => string | null;
5
+
6
+ let readToken: TokenProvider = () => null;
7
+ let handleUnauthorized: () => void = () => {};
8
+
9
+ /**
10
+ * Tell the client where the session lives.
11
+ *
12
+ * The client ships knowing nothing about auth so a project without accounts
13
+ * can delete `@/stores/auth` and touch nothing here: with no call to this
14
+ * function every request goes out unauthenticated and a 401 is just an error.
15
+ * `@/stores/auth` calls it at module load to wire the store in.
16
+ *
17
+ * @param options - Where to read the token and what to do on a 401.
18
+ */
19
+ export function configureApiAuth(options: {
20
+ getToken: TokenProvider;
21
+ onUnauthorized?: () => void;
22
+ }): void {
23
+ readToken = options.getToken;
24
+ handleUnauthorized = options.onUnauthorized ?? (() => {});
25
+ }
4
26
 
5
27
  /**
6
- * Typed HTTP client. Reads the bearer token from the auth store on every
7
- * request and points at `VITE_API_URL`.
28
+ * Typed HTTP client pointed at `VITE_API_URL`, reading the bearer token
29
+ * through whatever `configureApiAuth` registered.
8
30
  */
9
31
  export const api = createApiClient({
10
32
  baseURL: import.meta.env.VITE_API_URL ?? "http://127.0.0.1:8000",
11
- getToken: () => useAuth.getState().token,
12
- onUnauthorized: () => useAuth.getState().logout(),
33
+ getToken: () => readToken(),
34
+ onUnauthorized: () => handleUnauthorized(),
13
35
  });
14
36
 
15
37
  /** Stable, namespaced query keys for TanStack Query. */
@@ -1,5 +1,7 @@
1
1
  import { createAuthStore, createSelectors } from "tempest-react-sdk";
2
2
 
3
+ import { configureApiAuth } from "@/lib/api";
4
+
3
5
  /** The user shape your backend returns. Adjust to match your API. */
4
6
  export interface User {
5
7
  id: string;
@@ -13,3 +15,15 @@ export interface User {
13
15
  * subscribe to a single slice.
14
16
  */
15
17
  export const useAuth = createSelectors(createAuthStore<User>({ name: "app-auth" }));
18
+
19
+ /**
20
+ * Hand the store to the HTTP client.
21
+ *
22
+ * The dependency points this way on purpose: `@/lib/api` knows nothing about
23
+ * auth, so a project without accounts deletes this file and the client keeps
24
+ * working unauthenticated.
25
+ */
26
+ configureApiAuth({
27
+ getToken: () => useAuth.getState().token,
28
+ onUnauthorized: () => useAuth.getState().logout(),
29
+ });