@streamplace/components 0.6.37 → 1.0.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 (55) hide show
  1. package/package.json +8 -34
  2. package/LICENSE +0 -18
  3. package/README.md +0 -35
  4. package/dist/index.js +0 -6
  5. package/dist/livestream-provider/index.js +0 -20
  6. package/dist/livestream-provider/websocket.js +0 -41
  7. package/dist/livestream-store/chat.js +0 -162
  8. package/dist/livestream-store/context.js +0 -2
  9. package/dist/livestream-store/index.js +0 -3
  10. package/dist/livestream-store/livestream-state.js +0 -1
  11. package/dist/livestream-store/livestream-store.js +0 -39
  12. package/dist/livestream-store/websocket-consumer.js +0 -55
  13. package/dist/player-store/context.js +0 -2
  14. package/dist/player-store/index.js +0 -6
  15. package/dist/player-store/player-provider.js +0 -53
  16. package/dist/player-store/player-state.js +0 -22
  17. package/dist/player-store/player-store.js +0 -146
  18. package/dist/player-store/single-player-provider.js +0 -109
  19. package/dist/streamplace-provider/context.js +0 -2
  20. package/dist/streamplace-provider/index.js +0 -16
  21. package/dist/streamplace-provider/poller.js +0 -46
  22. package/dist/streamplace-provider/xrpc.js +0 -0
  23. package/dist/streamplace-store/index.js +0 -2
  24. package/dist/streamplace-store/streamplace-store.js +0 -37
  25. package/dist/streamplace-store/user.js +0 -47
  26. package/dist/streamplace-store/xrpc.js +0 -12
  27. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  28. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
  29. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
  30. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
  31. package/src/index.tsx +0 -6
  32. package/src/livestream-provider/index.tsx +0 -37
  33. package/src/livestream-provider/websocket.tsx +0 -47
  34. package/src/livestream-store/chat.tsx +0 -224
  35. package/src/livestream-store/context.tsx +0 -10
  36. package/src/livestream-store/index.tsx +0 -3
  37. package/src/livestream-store/livestream-state.tsx +0 -18
  38. package/src/livestream-store/livestream-store.tsx +0 -56
  39. package/src/livestream-store/websocket-consumer.tsx +0 -62
  40. package/src/player-store/context.tsx +0 -11
  41. package/src/player-store/index.tsx +0 -6
  42. package/src/player-store/player-provider.tsx +0 -90
  43. package/src/player-store/player-state.tsx +0 -159
  44. package/src/player-store/player-store.tsx +0 -217
  45. package/src/player-store/single-player-provider.tsx +0 -181
  46. package/src/streamplace-provider/context.tsx +0 -10
  47. package/src/streamplace-provider/index.tsx +0 -32
  48. package/src/streamplace-provider/poller.tsx +0 -55
  49. package/src/streamplace-provider/xrpc.tsx +0 -0
  50. package/src/streamplace-store/index.tsx +0 -2
  51. package/src/streamplace-store/streamplace-store.tsx +0 -89
  52. package/src/streamplace-store/user.tsx +0 -57
  53. package/src/streamplace-store/xrpc.tsx +0 -15
  54. package/tsconfig.json +0 -9
  55. package/tsconfig.tsbuildinfo +0 -1
package/package.json CHANGED
@@ -1,39 +1,13 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.6.37",
4
- "description": "Streamplace React (Native) Components",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "src/index.tsx",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.mjs",
11
- "default": "./dist/index.mjs"
12
- }
13
- },
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "package.json",
14
6
  "scripts": {
15
- "build": "tsc",
16
- "postinstall": "pnpm run build",
17
- "start": "tsc --watch --preserveWatchOutput"
18
- },
19
- "keywords": [
20
- "streamplace"
21
- ],
22
- "author": "Streamplace",
23
- "license": "MIT",
24
- "packageManager": "pnpm@10.11.0",
25
- "devDependencies": {
26
- "tsup": "^8.5.0"
27
- },
28
- "dependencies": {
29
- "@atproto/api": "^0.15.7",
30
- "react-native": "0.76.2",
31
- "react-use-websocket": "^4.13.0",
32
- "streamplace": "0.6.37",
33
- "zustand": "^5.0.5"
34
- },
35
- "peerDependencies": {
36
- "react": "*"
7
+ "test": "echo \"Error: no test specified\" && exit 1"
37
8
  },
38
- "gitHead": "87a2627518e509fd364199cb71657a94eac51066"
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "packageManager": "pnpm@9.14.4+sha512.c8180b3fbe4e4bca02c94234717896b5529740a6cbadf19fa78254270403ea2f27d4e1d46a08a0f56c89b63dc8ebfd3ee53326da720273794e6200fcf0d184ab"
39
13
  }
package/LICENSE DELETED
@@ -1,18 +0,0 @@
1
- Copyright (c) 2025 Streamplace.
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- this software and associated documentation files (the "Software"), to deal in
5
- the Software without restriction, including without limitation the rights to
6
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
- the Software, and to permit persons to whom the Software is furnished to do so,
8
- subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all
11
- copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md DELETED
@@ -1,35 +0,0 @@
1
- # @streamplace/components
2
-
3
- Heavily WIP but looks something like this:
4
-
5
- ```tsx
6
- import {
7
- StreamplaceProvider,
8
- LivestreamProvider,
9
- } from "@streamplace/components";
10
-
11
- export function Provider() {
12
- <StreamplaceProvider url="https://stream.place" oauthSession={userSession}>
13
- {/* Everything inside of here can access that Streamplace node */}
14
-
15
- <LivestreamProvider src="example.bsky.social" /* or did:plc:xxxx */>
16
- {/* Everything in here has an active subscription to the livestream
17
- context via Websocket; things like chat data and stream title */}
18
- <App />
19
- </LivestreamProvider>
20
- </StreamplaceProvider>;
21
- }
22
-
23
- export function App() {
24
- const chat = useChat();
25
- return (
26
- <View>
27
- {chat.map((msg) => (
28
- <Text>
29
- @{msg.author.handle}: {msg.record.text}
30
- </Text>
31
- ))}
32
- </View>
33
- );
34
- }
35
- ```
package/dist/index.js DELETED
@@ -1,6 +0,0 @@
1
- // barrel file :)
2
- export * from "./livestream-provider";
3
- export * from "./livestream-store";
4
- export * from "./player-store";
5
- export * from "./streamplace-provider";
6
- export * from "./streamplace-store";
@@ -1,20 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext, useRef } from "react";
3
- import { LivestreamContext, makeLivestreamStore } from "../livestream-store";
4
- import { useLivestreamWebsocket } from "./websocket";
5
- export function LivestreamProvider({ children, src, }) {
6
- const context = useContext(LivestreamContext);
7
- const store = useRef(makeLivestreamStore()).current;
8
- if (context) {
9
- // this is ok, there's use cases for having one in another
10
- // like having a player component that's independently usable
11
- // but can also be embedded within an entire livestream page
12
- return _jsx(_Fragment, { children: children });
13
- }
14
- window.livestreamStore = store;
15
- return (_jsx(LivestreamContext.Provider, { value: { store: store }, children: _jsx(LivestreamPoller, { src: src, children: children }) }));
16
- }
17
- export function LivestreamPoller({ children, src, }) {
18
- useLivestreamWebsocket(src);
19
- return _jsx(_Fragment, { children: children });
20
- }
@@ -1,41 +0,0 @@
1
- import { useRef } from "react";
2
- import useWebSocket from "react-use-websocket";
3
- import { useHandleWebsocketMessages } from "../livestream-store";
4
- import { useUrl } from "../streamplace-store";
5
- export function useLivestreamWebsocket(src) {
6
- const url = useUrl();
7
- const handleWebSocketMessages = useHandleWebsocketMessages();
8
- let wsUrl = url.replace(/^http\:/, "ws:");
9
- wsUrl = wsUrl.replace(/^https\:/, "wss:");
10
- const ref = useRef([]);
11
- const handle = useRef(null);
12
- const { readyState } = useWebSocket(`${wsUrl}/api/websocket/${src}`, {
13
- reconnectInterval: 1000,
14
- shouldReconnect: () => true,
15
- onOpen: () => {
16
- ref.current = [];
17
- },
18
- onError: (e) => {
19
- console.log("onError", e);
20
- },
21
- // spamming the redux store with messages causes a zillion re-renders,
22
- // so we batch them up a bit
23
- onMessage: (msg) => {
24
- try {
25
- const data = JSON.parse(msg.data);
26
- ref.current.push(data);
27
- if (handle.current) {
28
- return;
29
- }
30
- handle.current = setTimeout(() => {
31
- handleWebSocketMessages(ref.current);
32
- ref.current = [];
33
- handle.current = null;
34
- }, 250);
35
- }
36
- catch (e) {
37
- console.log("onMessage parse error", e);
38
- }
39
- },
40
- });
41
- }
@@ -1,162 +0,0 @@
1
- import { RichText } from "@atproto/api";
2
- import { isLink, isMention, } from "@atproto/api/dist/client/types/app/bsky/richtext/facet";
3
- import { useChatProfile, useDID, useHandle } from "../streamplace-store";
4
- import { usePDSAgent } from "../streamplace-store/xrpc";
5
- import { getStoreFromContext, useLivestreamStore } from "./livestream-store";
6
- export const useReplyToMessage = () => useLivestreamStore((state) => state.replyToMessage);
7
- export const useSetReplyToMessage = () => {
8
- const store = getStoreFromContext();
9
- return (message) => {
10
- store.setState({ replyToMessage: message });
11
- };
12
- };
13
- export const useCreateChatMessage = () => {
14
- const pdsAgent = usePDSAgent();
15
- const store = getStoreFromContext();
16
- const userDID = useDID();
17
- const userHandle = useHandle();
18
- const chatProfile = useChatProfile();
19
- return async (msg) => {
20
- if (!pdsAgent || !userDID) {
21
- throw new Error("No PDS agent or user DID found");
22
- }
23
- let state = store.getState();
24
- const streamerProfile = state.profile;
25
- if (!streamerProfile) {
26
- throw new Error("Profile not found");
27
- }
28
- const rt = new RichText({ text: msg.text });
29
- rt.detectFacetsWithoutResolution();
30
- const record = {
31
- text: msg.text,
32
- createdAt: new Date().toISOString(),
33
- streamer: streamerProfile.did,
34
- ...(msg.reply
35
- ? {
36
- reply: {
37
- root: {
38
- cid: msg.reply.cid,
39
- uri: msg.reply.uri,
40
- },
41
- parent: {
42
- cid: msg.reply.cid,
43
- uri: msg.reply.uri,
44
- },
45
- },
46
- }
47
- : {}),
48
- ...(rt.facets && rt.facets.length > 0
49
- ? {
50
- facets: rt.facets.map((facet) => ({
51
- index: facet.index,
52
- features: facet.features
53
- .filter((feature) => feature.$type === "app.bsky.richtext.facet#link" ||
54
- feature.$type === "app.bsky.richtext.facet#mention")
55
- .map((feature) => {
56
- if (isLink(feature)) {
57
- return {
58
- $type: "app.bsky.richtext.facet#link",
59
- uri: feature.uri,
60
- };
61
- }
62
- else if (isMention(feature)) {
63
- return {
64
- $type: "app.bsky.richtext.facet#mention",
65
- did: feature.did,
66
- };
67
- }
68
- else {
69
- throw new Error("invalid code path");
70
- }
71
- }),
72
- })),
73
- }
74
- : {}),
75
- };
76
- const localChat = {
77
- uri: `local-${Date.now()}`,
78
- cid: "",
79
- author: {
80
- did: userDID,
81
- handle: userHandle || userDID,
82
- },
83
- record: record,
84
- indexedAt: new Date().toISOString(),
85
- chatProfile: chatProfile || undefined,
86
- };
87
- state = reduceChat(state, [localChat], []);
88
- store.setState(state);
89
- await pdsAgent.com.atproto.repo.createRecord({
90
- repo: userDID,
91
- collection: "place.stream.chat.message",
92
- record,
93
- });
94
- };
95
- };
96
- const CHAT_LIMIT = 20;
97
- export const reduceChat = (state, messages, blocks) => {
98
- state = { ...state };
99
- let newChat = {
100
- ...state.chatIndex,
101
- };
102
- // Add new messages
103
- for (let message of messages) {
104
- const date = new Date(message.record.createdAt);
105
- const key = `${date.getTime()}-${message.uri}`;
106
- // Remove existing local message matching the server one
107
- if (!message.uri.startsWith("local-")) {
108
- const existingLocalMessageKey = Object.keys(newChat).find((k) => {
109
- const msg = newChat[k];
110
- return (msg.uri.startsWith("local-") &&
111
- msg.record.text === message.record.text &&
112
- msg.author.did === message.author.did);
113
- });
114
- if (existingLocalMessageKey) {
115
- delete newChat[existingLocalMessageKey];
116
- }
117
- }
118
- // Handle reply information for local-first messages
119
- if (message.record.reply) {
120
- const reply = message.record.reply;
121
- const parentUri = reply?.parent?.uri || reply?.root?.uri;
122
- if (parentUri) {
123
- // First try to find the parent message in our chat
124
- const parentMsgKey = Object.keys(newChat).find((k) => newChat[k].uri === parentUri);
125
- if (parentMsgKey) {
126
- // Found the parent message, add its info to our message
127
- const parentMsg = newChat[parentMsgKey];
128
- message = {
129
- ...message,
130
- replyTo: {
131
- cid: parentMsg.cid,
132
- uri: parentMsg.uri,
133
- author: parentMsg.author,
134
- record: parentMsg.record,
135
- chatProfile: parentMsg.chatProfile,
136
- indexedAt: parentMsg.indexedAt,
137
- },
138
- };
139
- }
140
- }
141
- }
142
- newChat[key] = message;
143
- }
144
- for (const block of blocks) {
145
- for (const [k, v] of Object.entries(newChat)) {
146
- if (v.author.did === block.record.subject) {
147
- delete newChat[k];
148
- }
149
- }
150
- }
151
- let newChatList = Object.values(newChat).sort((a, b) => new Date(a.record.createdAt) > new Date(b.record.createdAt) ? 1 : -1);
152
- newChatList = newChatList.slice(-CHAT_LIMIT);
153
- newChat = newChatList.reduce((acc, msg) => {
154
- acc[msg.uri] = msg;
155
- return acc;
156
- }, {});
157
- return {
158
- ...state,
159
- chatIndex: newChat,
160
- chat: newChatList,
161
- };
162
- };
@@ -1,2 +0,0 @@
1
- import { createContext } from "react";
2
- export const LivestreamContext = createContext(null);
@@ -1,3 +0,0 @@
1
- export * from "./chat";
2
- export * from "./context";
3
- export * from "./livestream-store";
@@ -1 +0,0 @@
1
- export {};
@@ -1,39 +0,0 @@
1
- import { useContext } from "react";
2
- import { createStore, useStore } from "zustand";
3
- import { LivestreamContext } from "./context";
4
- import { handleWebSocketMessages } from "./websocket-consumer";
5
- export const makeLivestreamStore = () => {
6
- return createStore()((set) => ({
7
- profile: null,
8
- chatIndex: {},
9
- chat: [],
10
- livestream: null,
11
- viewers: null,
12
- segment: null,
13
- renditions: [],
14
- replyToMessage: null,
15
- }));
16
- };
17
- export function getStoreFromContext() {
18
- const context = useContext(LivestreamContext);
19
- if (!context) {
20
- throw new Error("useLivestreamStore must be used within a LivestreamProvider");
21
- }
22
- return context.store;
23
- }
24
- export function useLivestreamStore(selector) {
25
- const store = getStoreFromContext();
26
- return useStore(store, selector);
27
- }
28
- export const useHandleWebsocketMessages = () => {
29
- const store = getStoreFromContext();
30
- return (messages) => {
31
- store.setState((state) => handleWebSocketMessages(state, messages));
32
- };
33
- };
34
- export const useChat = () => useLivestreamStore((x) => x.chat);
35
- export const useProfile = () => useLivestreamStore((x) => x.profile);
36
- export const useViewers = () => useLivestreamStore((x) => x.viewers);
37
- export const useLivestream = () => useLivestreamStore((x) => x.livestream);
38
- export const useSegment = () => useLivestreamStore((x) => x.segment);
39
- export const useRenditions = () => useLivestreamStore((x) => x.renditions);
@@ -1,55 +0,0 @@
1
- import { AppBskyActorDefs } from "@atproto/api";
2
- import { PlaceStreamChatDefs, PlaceStreamDefs, PlaceStreamLivestream, PlaceStreamSegment, } from "streamplace";
3
- import { reduceChat } from "./chat";
4
- export const handleWebSocketMessages = (state, messages) => {
5
- for (const message of messages) {
6
- if (PlaceStreamLivestream.isLivestreamView(message)) {
7
- state = {
8
- ...state,
9
- livestream: message,
10
- };
11
- }
12
- else if (PlaceStreamLivestream.isViewerCount(message)) {
13
- state = {
14
- ...state,
15
- viewers: message.count,
16
- };
17
- }
18
- else if (PlaceStreamChatDefs.isMessageView(message)) {
19
- // Explicitly map MessageView to MessageViewHydrated
20
- const hydrated = {
21
- uri: message.uri,
22
- cid: message.cid,
23
- author: message.author,
24
- record: message.record,
25
- indexedAt: message.indexedAt,
26
- chatProfile: message.chatProfile,
27
- replyTo: message.replyTo,
28
- };
29
- state = reduceChat(state, [hydrated], []);
30
- }
31
- else if (PlaceStreamSegment.isRecord(message)) {
32
- state = {
33
- ...state,
34
- segment: message,
35
- };
36
- }
37
- else if (PlaceStreamDefs.isBlockView(message)) {
38
- const block = message;
39
- state = reduceChat(state, [], [block]);
40
- }
41
- else if (PlaceStreamDefs.isRenditions(message)) {
42
- state = {
43
- ...state,
44
- renditions: message.renditions,
45
- };
46
- }
47
- else if (AppBskyActorDefs.isProfileViewBasic(message)) {
48
- state = {
49
- ...state,
50
- profile: message,
51
- };
52
- }
53
- }
54
- return reduceChat(state, [], []);
55
- };
@@ -1,2 +0,0 @@
1
- import { createContext } from "react";
2
- export const PlayerContext = createContext(null);
@@ -1,6 +0,0 @@
1
- // barrel file :)
2
- export * from "./context";
3
- export * from "./player-provider";
4
- export * from "./player-state";
5
- export * from "./player-store";
6
- export * from "./single-player-provider";
@@ -1,53 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback, useMemo, useState } from "react";
3
- import { PlayerContext } from "./context";
4
- import { makePlayerStore } from "./player-store";
5
- export const PlayerProvider = ({ children, initialPlayers = [], defaultId = Math.random().toString(36).slice(8), }) => {
6
- const [players, setPlayers] = useState(() => {
7
- // Initialize with any initial player IDs provided
8
- const initialPlayerStores = {};
9
- for (const playerId of initialPlayers) {
10
- initialPlayerStores[playerId] = makePlayerStore(playerId);
11
- }
12
- // Always create at least one player by default
13
- if (initialPlayers.length === 0) {
14
- initialPlayerStores[defaultId] = makePlayerStore(defaultId);
15
- }
16
- return initialPlayerStores;
17
- });
18
- const createPlayer = useCallback((id) => {
19
- console.log("Creating new player");
20
- const playerId = id || Math.random().toString(36).slice(8);
21
- const playerStore = makePlayerStore(playerId);
22
- setPlayers((prev) => ({
23
- ...prev,
24
- [playerId]: playerStore,
25
- }));
26
- return playerId;
27
- }, []);
28
- const removePlayer = useCallback((id) => {
29
- setPlayers((prev) => {
30
- // Don't remove the last player
31
- if (Object.keys(prev).length <= 1) {
32
- console.warn("Cannot remove the last player");
33
- return prev;
34
- }
35
- const newPlayers = { ...prev };
36
- delete newPlayers[id];
37
- return newPlayers;
38
- });
39
- }, []);
40
- const contextValue = useMemo(() => ({
41
- players,
42
- createPlayer,
43
- removePlayer,
44
- }), [players, createPlayer, removePlayer]);
45
- return (_jsx(PlayerContext.Provider, { value: contextValue, children: children }));
46
- };
47
- // HOC to wrap components that need player context
48
- export function withPlayerProvider(Component) {
49
- return function WithPlayerProvider(props) {
50
- const { initialPlayers, ...componentProps } = props;
51
- return (_jsx(PlayerProvider, { initialPlayers: initialPlayers, children: _jsx(Component, { ...componentProps }) }));
52
- };
53
- }
@@ -1,22 +0,0 @@
1
- export var PlayerProtocol;
2
- (function (PlayerProtocol) {
3
- PlayerProtocol["WEBRTC"] = "webrtc";
4
- PlayerProtocol["HLS"] = "hls";
5
- PlayerProtocol["PROGRESSIVE_MP4"] = "progressive-mp4";
6
- PlayerProtocol["PROGRESSIVE_WEBM"] = "progressive-webm";
7
- })(PlayerProtocol || (PlayerProtocol = {}));
8
- export var PlayerStatus;
9
- (function (PlayerStatus) {
10
- PlayerStatus["START"] = "start";
11
- PlayerStatus["PLAYING"] = "playing";
12
- PlayerStatus["STALLED"] = "stalled";
13
- PlayerStatus["SUSPEND"] = "suspend";
14
- PlayerStatus["WAITING"] = "waiting";
15
- PlayerStatus["PAUSE"] = "pause";
16
- PlayerStatus["MUTE"] = "mute";
17
- })(PlayerStatus || (PlayerStatus = {}));
18
- export var IngestMediaSource;
19
- (function (IngestMediaSource) {
20
- IngestMediaSource["USER"] = "user";
21
- IngestMediaSource["DISPLAY"] = "display";
22
- })(IngestMediaSource || (IngestMediaSource = {}));