@streamplace/components 0.8.18 → 0.9.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/dist/components/chat/chat-box.d.ts +1 -1
- package/dist/components/chat/chat-box.d.ts.map +1 -1
- package/dist/components/chat/chat-box.js +3 -0
- package/dist/components/chat/chat-box.js.map +1 -1
- package/dist/components/chat/mod-view.d.ts +4 -2
- package/dist/components/chat/mod-view.d.ts.map +1 -1
- package/dist/components/chat/mod-view.js +142 -42
- package/dist/components/chat/mod-view.js.map +1 -1
- package/dist/components/dashboard/chat-panel.d.ts +2 -1
- package/dist/components/dashboard/chat-panel.d.ts.map +1 -1
- package/dist/components/dashboard/chat-panel.js +2 -3
- package/dist/components/dashboard/chat-panel.js.map +1 -1
- package/dist/components/dashboard/index.d.ts +1 -0
- package/dist/components/dashboard/index.d.ts.map +1 -1
- package/dist/components/dashboard/index.js +3 -1
- package/dist/components/dashboard/index.js.map +1 -1
- package/dist/components/dashboard/moderator-panel.d.ts +7 -0
- package/dist/components/dashboard/moderator-panel.d.ts.map +1 -0
- package/dist/components/dashboard/moderator-panel.js +256 -0
- package/dist/components/dashboard/moderator-panel.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +1 -1
- package/dist/components/ui/menu.d.ts.map +1 -1
- package/dist/components/ui/menu.js +2 -2
- package/dist/components/ui/menu.js.map +1 -1
- package/dist/crypto-polyfill.native.js +7 -1
- package/dist/crypto-polyfill.native.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useDocumentTitle.d.ts +6 -0
- package/dist/hooks/useDocumentTitle.d.ts.map +1 -0
- package/dist/hooks/useDocumentTitle.js +40 -0
- package/dist/hooks/useDocumentTitle.js.map +1 -0
- package/dist/lib/theme/atoms.d.ts +138 -138
- package/dist/lib/theme/branded-theme-provider.d.ts +13 -0
- package/dist/lib/theme/branded-theme-provider.d.ts.map +1 -0
- package/dist/lib/theme/branded-theme-provider.js +34 -0
- package/dist/lib/theme/branded-theme-provider.js.map +1 -0
- package/dist/lib/theme/index.d.ts +1 -0
- package/dist/lib/theme/index.d.ts.map +1 -1
- package/dist/lib/theme/index.js +4 -1
- package/dist/lib/theme/index.js.map +1 -1
- package/dist/livestream-store/chat.d.ts +1 -1
- package/dist/livestream-store/chat.d.ts.map +1 -1
- package/dist/livestream-store/chat.js +1 -3
- package/dist/livestream-store/chat.js.map +1 -1
- package/dist/livestream-store/livestream-state.d.ts +3 -1
- package/dist/livestream-store/livestream-state.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.d.ts.map +1 -1
- package/dist/livestream-store/livestream-store.js +2 -0
- package/dist/livestream-store/livestream-store.js.map +1 -1
- package/dist/livestream-store/stream-key.d.ts +1 -0
- package/dist/livestream-store/stream-key.d.ts.map +1 -1
- package/dist/livestream-store/stream-key.js +2 -0
- package/dist/livestream-store/stream-key.js.map +1 -1
- package/dist/livestream-store/websocket-consumer.d.ts.map +1 -1
- package/dist/livestream-store/websocket-consumer.js +48 -0
- package/dist/livestream-store/websocket-consumer.js.map +1 -1
- package/dist/streamplace-provider/index.d.ts +3 -0
- package/dist/streamplace-provider/index.d.ts.map +1 -1
- package/dist/streamplace-provider/index.js +12 -1
- package/dist/streamplace-provider/index.js.map +1 -1
- package/dist/streamplace-store/block.d.ts +36 -2
- package/dist/streamplace-store/block.d.ts.map +1 -1
- package/dist/streamplace-store/block.js +121 -18
- package/dist/streamplace-store/block.js.map +1 -1
- package/dist/streamplace-store/branding.d.ts +27 -0
- package/dist/streamplace-store/branding.d.ts.map +1 -0
- package/dist/streamplace-store/branding.js +195 -0
- package/dist/streamplace-store/branding.js.map +1 -0
- package/dist/streamplace-store/index.d.ts +4 -0
- package/dist/streamplace-store/index.d.ts.map +1 -1
- package/dist/streamplace-store/index.js +4 -0
- package/dist/streamplace-store/index.js.map +1 -1
- package/dist/streamplace-store/moderation.d.ts +16 -0
- package/dist/streamplace-store/moderation.d.ts.map +1 -0
- package/dist/streamplace-store/moderation.js +141 -0
- package/dist/streamplace-store/moderation.js.map +1 -0
- package/dist/streamplace-store/moderator-management.d.ts +44 -0
- package/dist/streamplace-store/moderator-management.d.ts.map +1 -0
- package/dist/streamplace-store/moderator-management.js +136 -0
- package/dist/streamplace-store/moderator-management.js.map +1 -0
- package/dist/streamplace-store/streamplace-store.d.ts +6 -0
- package/dist/streamplace-store/streamplace-store.d.ts.map +1 -1
- package/dist/streamplace-store/streamplace-store.js +6 -0
- package/dist/streamplace-store/streamplace-store.js.map +1 -1
- package/dist/streamplace-store/xrpc.d.ts +1 -0
- package/dist/streamplace-store/xrpc.d.ts.map +1 -1
- package/dist/streamplace-store/xrpc.js +16 -0
- package/dist/streamplace-store/xrpc.js.map +1 -1
- package/locales/en-US/settings.ftl +91 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +3 -3
- package/src/components/chat/chat-box.tsx +3 -1
- package/src/components/chat/mod-view.tsx +431 -121
- package/src/components/dashboard/chat-panel.tsx +2 -1
- package/src/components/dashboard/index.tsx +1 -0
- package/src/components/dashboard/moderator-panel.tsx +632 -0
- package/src/components/ui/menu.tsx +1 -2
- package/src/crypto-polyfill.native.tsx +8 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDocumentTitle.tsx +45 -0
- package/src/lib/theme/branded-theme-provider.tsx +58 -0
- package/src/lib/theme/index.ts +3 -0
- package/src/livestream-store/chat.tsx +0 -2
- package/src/livestream-store/livestream-state.tsx +5 -0
- package/src/livestream-store/livestream-store.tsx +2 -0
- package/src/livestream-store/stream-key.tsx +3 -0
- package/src/livestream-store/websocket-consumer.tsx +60 -0
- package/src/streamplace-provider/index.tsx +23 -4
- package/src/streamplace-store/block.tsx +139 -19
- package/src/streamplace-store/branding.tsx +216 -0
- package/src/streamplace-store/index.tsx +4 -0
- package/src/streamplace-store/moderation.tsx +185 -0
- package/src/streamplace-store/moderator-management.tsx +175 -0
- package/src/streamplace-store/streamplace-store.tsx +15 -0
- package/src/streamplace-store/xrpc.tsx +18 -1
- package/dist/assets/emoji-data.json +0 -19371
- package/src/assets/emoji-data.json +0 -19371
|
@@ -2,12 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useCreateBlockRecord = useCreateBlockRecord;
|
|
4
4
|
exports.useCreateHideChatRecord = useCreateHideChatRecord;
|
|
5
|
+
exports.useUpdateLivestreamRecord = useUpdateLivestreamRecord;
|
|
5
6
|
const react_1 = require("react");
|
|
6
7
|
const xrpc_1 = require("./xrpc");
|
|
8
|
+
/**
|
|
9
|
+
* Hook to create a block record (ban user from chat).
|
|
10
|
+
*
|
|
11
|
+
* When the caller is the stream owner (agent.did === streamerDID), creates the
|
|
12
|
+
* block record directly via ATProto writes to their repo.
|
|
13
|
+
*
|
|
14
|
+
* When the caller is a delegated moderator, uses the place.stream.moderation.createBlock
|
|
15
|
+
* XRPC endpoint which validates permissions and creates the record using the
|
|
16
|
+
* streamer's OAuth session.
|
|
17
|
+
*/
|
|
7
18
|
function useCreateBlockRecord() {
|
|
8
19
|
let agent = (0, xrpc_1.usePDSAgent)();
|
|
9
20
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
10
|
-
const createBlock = async (subjectDID) => {
|
|
21
|
+
const createBlock = async (subjectDID, streamerDID) => {
|
|
11
22
|
if (!agent) {
|
|
12
23
|
throw new Error("No PDS agent found");
|
|
13
24
|
}
|
|
@@ -16,15 +27,24 @@ function useCreateBlockRecord() {
|
|
|
16
27
|
}
|
|
17
28
|
setIsLoading(true);
|
|
18
29
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
30
|
+
// If no streamerDID provided or caller is the streamer, use direct ATProto write
|
|
31
|
+
if (!streamerDID || agent.did === streamerDID) {
|
|
32
|
+
const record = {
|
|
33
|
+
$type: "app.bsky.graph.block",
|
|
34
|
+
subject: subjectDID,
|
|
35
|
+
createdAt: new Date().toISOString(),
|
|
36
|
+
};
|
|
37
|
+
const result = await agent.com.atproto.repo.createRecord({
|
|
38
|
+
repo: agent.did,
|
|
39
|
+
collection: "app.bsky.graph.block",
|
|
40
|
+
record,
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
// Otherwise, use delegated moderation endpoint
|
|
45
|
+
const result = await agent.place.stream.moderation.createBlock({
|
|
46
|
+
streamer: streamerDID,
|
|
21
47
|
subject: subjectDID,
|
|
22
|
-
createdAt: new Date().toISOString(),
|
|
23
|
-
};
|
|
24
|
-
const result = await agent.com.atproto.repo.createRecord({
|
|
25
|
-
repo: agent.did,
|
|
26
|
-
collection: "app.bsky.graph.block",
|
|
27
|
-
record,
|
|
28
48
|
});
|
|
29
49
|
return result;
|
|
30
50
|
}
|
|
@@ -34,10 +54,20 @@ function useCreateBlockRecord() {
|
|
|
34
54
|
};
|
|
35
55
|
return { createBlock, isLoading };
|
|
36
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Hook to create a gate record (hide a chat message).
|
|
59
|
+
*
|
|
60
|
+
* When the caller is the stream owner (agent.did === streamerDID), creates the
|
|
61
|
+
* gate record directly via ATProto writes to their repo.
|
|
62
|
+
*
|
|
63
|
+
* When the caller is a delegated moderator, uses the place.stream.moderation.createGate
|
|
64
|
+
* XRPC endpoint which validates permissions and creates the record using the
|
|
65
|
+
* streamer's OAuth session.
|
|
66
|
+
*/
|
|
37
67
|
function useCreateHideChatRecord() {
|
|
38
68
|
let agent = (0, xrpc_1.usePDSAgent)();
|
|
39
69
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
40
|
-
const createHideChat = async (chatMessageUri) => {
|
|
70
|
+
const createHideChat = async (chatMessageUri, streamerDID) => {
|
|
41
71
|
if (!agent) {
|
|
42
72
|
throw new Error("No PDS agent found");
|
|
43
73
|
}
|
|
@@ -46,14 +76,23 @@ function useCreateHideChatRecord() {
|
|
|
46
76
|
}
|
|
47
77
|
setIsLoading(true);
|
|
48
78
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
// If no streamerDID provided or caller is the streamer, use direct ATProto write
|
|
80
|
+
if (!streamerDID || agent.did === streamerDID) {
|
|
81
|
+
const record = {
|
|
82
|
+
$type: "place.stream.chat.gate",
|
|
83
|
+
hiddenMessage: chatMessageUri,
|
|
84
|
+
};
|
|
85
|
+
const result = await agent.com.atproto.repo.createRecord({
|
|
86
|
+
repo: agent.did,
|
|
87
|
+
collection: "place.stream.chat.gate",
|
|
88
|
+
record,
|
|
89
|
+
});
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
// Otherwise, use delegated moderation endpoint
|
|
93
|
+
const result = await agent.place.stream.moderation.createGate({
|
|
94
|
+
streamer: streamerDID,
|
|
95
|
+
messageUri: chatMessageUri,
|
|
57
96
|
});
|
|
58
97
|
return result;
|
|
59
98
|
}
|
|
@@ -63,4 +102,68 @@ function useCreateHideChatRecord() {
|
|
|
63
102
|
};
|
|
64
103
|
return { createHideChat, isLoading };
|
|
65
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Hook to update a livestream record (update stream title).
|
|
107
|
+
*
|
|
108
|
+
* When the caller is the stream owner (agent.did === streamerDID), updates the
|
|
109
|
+
* livestream record directly via ATProto writes to their repo.
|
|
110
|
+
*
|
|
111
|
+
* When the caller is a delegated moderator, uses the place.stream.moderation.updateLivestream
|
|
112
|
+
* XRPC endpoint which validates permissions and updates the record using the
|
|
113
|
+
* streamer's OAuth session.
|
|
114
|
+
*/
|
|
115
|
+
function useUpdateLivestreamRecord() {
|
|
116
|
+
let agent = (0, xrpc_1.usePDSAgent)();
|
|
117
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
118
|
+
const updateLivestream = async (livestreamUri, title, streamerDID) => {
|
|
119
|
+
if (!agent) {
|
|
120
|
+
throw new Error("No PDS agent found");
|
|
121
|
+
}
|
|
122
|
+
if (!agent.did) {
|
|
123
|
+
throw new Error("No user DID found, assuming not logged in");
|
|
124
|
+
}
|
|
125
|
+
setIsLoading(true);
|
|
126
|
+
try {
|
|
127
|
+
// If no streamerDID provided or caller is the streamer, use direct ATProto write
|
|
128
|
+
if (!streamerDID || agent.did === streamerDID) {
|
|
129
|
+
// Extract rkey from URI
|
|
130
|
+
const rkey = livestreamUri.split("/").pop();
|
|
131
|
+
if (!rkey) {
|
|
132
|
+
throw new Error("Invalid livestream URI");
|
|
133
|
+
}
|
|
134
|
+
// Get existing record to copy fields
|
|
135
|
+
const getResult = await agent.com.atproto.repo.getRecord({
|
|
136
|
+
repo: agent.did,
|
|
137
|
+
collection: "place.stream.livestream",
|
|
138
|
+
rkey,
|
|
139
|
+
});
|
|
140
|
+
const oldRecord = getResult.data.value;
|
|
141
|
+
// Create new record (don't edit - old records are "chapter markers")
|
|
142
|
+
// Spread entire record to preserve all fields (agent, canonicalUrl, notificationSettings, etc.)
|
|
143
|
+
const record = {
|
|
144
|
+
...oldRecord,
|
|
145
|
+
title: title, // Override title
|
|
146
|
+
createdAt: new Date().toISOString(), // Override timestamp for new chapter marker
|
|
147
|
+
};
|
|
148
|
+
const result = await agent.com.atproto.repo.createRecord({
|
|
149
|
+
repo: agent.did,
|
|
150
|
+
collection: "place.stream.livestream",
|
|
151
|
+
record,
|
|
152
|
+
});
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
// Otherwise, use delegated moderation endpoint
|
|
156
|
+
const result = await agent.place.stream.moderation.updateLivestream({
|
|
157
|
+
streamer: streamerDID,
|
|
158
|
+
livestreamUri: livestreamUri,
|
|
159
|
+
title: title,
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
setIsLoading(false);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
return { updateLivestream, isLoading };
|
|
168
|
+
}
|
|
66
169
|
//# sourceMappingURL=block.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/streamplace-store/block.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/streamplace-store/block.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface BrandingAsset {
|
|
2
|
+
key: string;
|
|
3
|
+
mimeType: string;
|
|
4
|
+
url?: string;
|
|
5
|
+
data?: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function useFetchBroadcasterDID(): () => Promise<void>;
|
|
10
|
+
export declare function useFetchBranding(): ({ force }?: {
|
|
11
|
+
force?: boolean | undefined;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export declare function useBrandingAsset(key: string): BrandingAsset | undefined;
|
|
14
|
+
export declare function useMainLogo(): string | undefined;
|
|
15
|
+
export declare function useFavicon(): string | undefined;
|
|
16
|
+
export declare function useSiteTitle(): string;
|
|
17
|
+
export declare function useSiteDescription(): string;
|
|
18
|
+
export declare function usePrimaryColor(): string;
|
|
19
|
+
export declare function useAccentColor(): string;
|
|
20
|
+
export declare function useDefaultStreamer(): string | undefined;
|
|
21
|
+
export declare function useSidebarBackgroundImage(): BrandingAsset | undefined;
|
|
22
|
+
export declare function useLegalLinks(): {
|
|
23
|
+
text: string;
|
|
24
|
+
url: string;
|
|
25
|
+
}[];
|
|
26
|
+
export declare function useBrandingAutoFetch(): void;
|
|
27
|
+
//# sourceMappingURL=branding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/streamplace-store/branding.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,sBAAsB,wBAsBrC;AAGD,wBAAgB,gBAAgB;;oBAqF/B;AAGD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEvE;AAGD,wBAAgB,WAAW,IAAI,MAAM,GAAG,SAAS,CAGhD;AAGD,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CAG/C;AAGD,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAGD,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AAGD,wBAAgB,cAAc,IAAI,MAAM,CAGvC;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAGvD;AAGD,wBAAgB,yBAAyB,IAAI,aAAa,GAAG,SAAS,CAErE;AAGD,wBAAgB,aAAa,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAU/D;AAGD,wBAAgB,oBAAoB,SASnC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useFetchBroadcasterDID = useFetchBroadcasterDID;
|
|
4
|
+
exports.useFetchBranding = useFetchBranding;
|
|
5
|
+
exports.useBrandingAsset = useBrandingAsset;
|
|
6
|
+
exports.useMainLogo = useMainLogo;
|
|
7
|
+
exports.useFavicon = useFavicon;
|
|
8
|
+
exports.useSiteTitle = useSiteTitle;
|
|
9
|
+
exports.useSiteDescription = useSiteDescription;
|
|
10
|
+
exports.usePrimaryColor = usePrimaryColor;
|
|
11
|
+
exports.useAccentColor = useAccentColor;
|
|
12
|
+
exports.useDefaultStreamer = useDefaultStreamer;
|
|
13
|
+
exports.useSidebarBackgroundImage = useSidebarBackgroundImage;
|
|
14
|
+
exports.useLegalLinks = useLegalLinks;
|
|
15
|
+
exports.useBrandingAutoFetch = useBrandingAutoFetch;
|
|
16
|
+
const tslib_1 = require("tslib");
|
|
17
|
+
const react_1 = require("react");
|
|
18
|
+
const storage_1 = tslib_1.__importDefault(require("../storage"));
|
|
19
|
+
const streamplace_store_1 = require("./streamplace-store");
|
|
20
|
+
const xrpc_1 = require("./xrpc");
|
|
21
|
+
// helper to convert blob to base64
|
|
22
|
+
const blobToBase64 = (blob) => {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const reader = new FileReader();
|
|
25
|
+
reader.onloadend = () => resolve(reader.result);
|
|
26
|
+
reader.onerror = reject;
|
|
27
|
+
reader.readAsDataURL(blob);
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
// hook to fetch broadcaster DID (unauthenticated)
|
|
31
|
+
function useFetchBroadcasterDID() {
|
|
32
|
+
const streamplaceAgent = (0, xrpc_1.usePossiblyUnauthedPDSAgent)();
|
|
33
|
+
const store = (0, streamplace_store_1.getStreamplaceStoreFromContext)();
|
|
34
|
+
return (0, react_1.useCallback)(async () => {
|
|
35
|
+
try {
|
|
36
|
+
if (!streamplaceAgent) {
|
|
37
|
+
throw new Error("Streamplace agent not available");
|
|
38
|
+
}
|
|
39
|
+
const result = await streamplaceAgent.place.stream.broadcast.getBroadcaster();
|
|
40
|
+
store.setState({ broadcasterDID: result.data.broadcaster });
|
|
41
|
+
if (result.data.server) {
|
|
42
|
+
store.setState({ serverDID: result.data.server });
|
|
43
|
+
}
|
|
44
|
+
if (result.data.admins) {
|
|
45
|
+
store.setState({ adminDIDs: result.data.admins });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error("Failed to fetch broadcaster DID:", err);
|
|
50
|
+
}
|
|
51
|
+
}, [streamplaceAgent, store]);
|
|
52
|
+
}
|
|
53
|
+
// hook to fetch branding data from the server
|
|
54
|
+
function useFetchBranding() {
|
|
55
|
+
const streamplaceAgent = (0, xrpc_1.usePossiblyUnauthedPDSAgent)();
|
|
56
|
+
const broadcasterDID = (0, streamplace_store_1.useStreamplaceStore)((state) => state.broadcasterDID);
|
|
57
|
+
const url = (0, streamplace_store_1.useStreamplaceStore)((state) => state.url);
|
|
58
|
+
const store = (0, streamplace_store_1.getStreamplaceStoreFromContext)();
|
|
59
|
+
return (0, react_1.useCallback)(async ({ force = true } = {}) => {
|
|
60
|
+
if (!broadcasterDID)
|
|
61
|
+
return;
|
|
62
|
+
try {
|
|
63
|
+
store.setState({ brandingLoading: true });
|
|
64
|
+
// check localStorage first
|
|
65
|
+
const cacheKey = `branding:${broadcasterDID}`;
|
|
66
|
+
const cached = await storage_1.default.getItem(cacheKey);
|
|
67
|
+
if (!force && cached) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(cached);
|
|
70
|
+
// check if cache is less than 1 hour old
|
|
71
|
+
if (Date.now() - parsed.timestamp < 60 * 60 * 1000) {
|
|
72
|
+
store.setState({
|
|
73
|
+
branding: parsed.data,
|
|
74
|
+
brandingLoading: false,
|
|
75
|
+
brandingError: null,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
// invalid cache, continue to fetch
|
|
82
|
+
console.warn("Invalid branding cache, refetching", e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// fetch branding metadata from server
|
|
86
|
+
if (!streamplaceAgent) {
|
|
87
|
+
throw new Error("Streamplace agent not available");
|
|
88
|
+
}
|
|
89
|
+
const res = await streamplaceAgent.place.stream.branding.getBranding({
|
|
90
|
+
broadcaster: broadcasterDID,
|
|
91
|
+
});
|
|
92
|
+
const assets = res.data.assets;
|
|
93
|
+
// convert assets array to keyed object and fetch blob data
|
|
94
|
+
const brandingMap = {};
|
|
95
|
+
for (const asset of assets) {
|
|
96
|
+
brandingMap[asset.key] = { ...asset };
|
|
97
|
+
// if data is already inline (text assets), use it directly
|
|
98
|
+
if (asset.data) {
|
|
99
|
+
brandingMap[asset.key].data = asset.data;
|
|
100
|
+
}
|
|
101
|
+
else if (asset.url) {
|
|
102
|
+
// for images, construct full URL and fetch blob
|
|
103
|
+
const fullUrl = `${url}${asset.url}`;
|
|
104
|
+
const blobRes = await fetch(fullUrl);
|
|
105
|
+
const blob = await blobRes.blob();
|
|
106
|
+
brandingMap[asset.key].data = await blobToBase64(blob);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// cache in localStorage
|
|
110
|
+
storage_1.default.setItem(cacheKey, JSON.stringify({
|
|
111
|
+
timestamp: Date.now(),
|
|
112
|
+
data: brandingMap,
|
|
113
|
+
}));
|
|
114
|
+
store.setState({
|
|
115
|
+
branding: brandingMap,
|
|
116
|
+
brandingLoading: false,
|
|
117
|
+
brandingError: null,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
console.error("Failed to fetch branding:", err);
|
|
122
|
+
store.setState({
|
|
123
|
+
brandingLoading: false,
|
|
124
|
+
brandingError: err.message || "Failed to fetch branding",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}, [broadcasterDID, streamplaceAgent, url, store]);
|
|
128
|
+
}
|
|
129
|
+
// hook to get a specific branding asset by key
|
|
130
|
+
function useBrandingAsset(key) {
|
|
131
|
+
return (0, streamplace_store_1.useStreamplaceStore)((state) => state.branding?.[key]);
|
|
132
|
+
}
|
|
133
|
+
// convenience hook for main logo
|
|
134
|
+
function useMainLogo() {
|
|
135
|
+
const asset = useBrandingAsset("mainLogo");
|
|
136
|
+
return asset?.data;
|
|
137
|
+
}
|
|
138
|
+
// convenience hook for favicon
|
|
139
|
+
function useFavicon() {
|
|
140
|
+
const asset = useBrandingAsset("favicon");
|
|
141
|
+
return asset?.data;
|
|
142
|
+
}
|
|
143
|
+
// convenience hook for site title
|
|
144
|
+
function useSiteTitle() {
|
|
145
|
+
const asset = useBrandingAsset("siteTitle");
|
|
146
|
+
return asset?.data || "My Streamplace Station";
|
|
147
|
+
}
|
|
148
|
+
// convenience hook for site description
|
|
149
|
+
function useSiteDescription() {
|
|
150
|
+
const asset = useBrandingAsset("siteDescription");
|
|
151
|
+
return asset?.data || "Live streaming platform";
|
|
152
|
+
}
|
|
153
|
+
// convenience hook for primary color
|
|
154
|
+
function usePrimaryColor() {
|
|
155
|
+
const asset = useBrandingAsset("primaryColor");
|
|
156
|
+
return asset?.data || "#6366f1";
|
|
157
|
+
}
|
|
158
|
+
// convenience hook for accent color
|
|
159
|
+
function useAccentColor() {
|
|
160
|
+
const asset = useBrandingAsset("accentColor");
|
|
161
|
+
return asset?.data || "#8b5cf6";
|
|
162
|
+
}
|
|
163
|
+
// convenience hook for default streamer
|
|
164
|
+
function useDefaultStreamer() {
|
|
165
|
+
const asset = useBrandingAsset("defaultStreamer");
|
|
166
|
+
return asset?.data || undefined;
|
|
167
|
+
}
|
|
168
|
+
// convenience hook for sidebar background image
|
|
169
|
+
function useSidebarBackgroundImage() {
|
|
170
|
+
return useBrandingAsset("sidebarBackgroundImage");
|
|
171
|
+
}
|
|
172
|
+
// convenience hook for legal links
|
|
173
|
+
function useLegalLinks() {
|
|
174
|
+
const asset = useBrandingAsset("legalLinks");
|
|
175
|
+
if (!asset?.data) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
return JSON.parse(asset.data);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// hook to auto-fetch branding when broadcaster changes
|
|
186
|
+
function useBrandingAutoFetch() {
|
|
187
|
+
const fetchBranding = useFetchBranding();
|
|
188
|
+
const broadcasterDID = (0, streamplace_store_1.useStreamplaceStore)((state) => state.broadcasterDID);
|
|
189
|
+
(0, react_1.useEffect)(() => {
|
|
190
|
+
if (broadcasterDID) {
|
|
191
|
+
fetchBranding();
|
|
192
|
+
}
|
|
193
|
+
}, [broadcasterDID, fetchBranding]);
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=branding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/streamplace-store/branding.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/streamplace-store/index.tsx"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/streamplace-store/index.tsx"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,QAAQ,CAAC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./block"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./branding"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./moderation"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./moderator-management"), exports);
|
|
4
8
|
tslib_1.__exportStar(require("./stream"), exports);
|
|
5
9
|
tslib_1.__exportStar(require("./streamplace-store"), exports);
|
|
6
10
|
tslib_1.__exportStar(require("./user"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/streamplace-store/index.tsx"],"names":[],"mappings":";;;AAAA,mDAAyB;AACzB,8DAAoC;AACpC,iDAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/streamplace-store/index.tsx"],"names":[],"mappings":";;;AAAA,kDAAwB;AACxB,qDAA2B;AAC3B,uDAA6B;AAC7B,iEAAuC;AACvC,mDAAyB;AACzB,8DAAoC;AACpC,iDAAuB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ModerationPermissions {
|
|
2
|
+
canBan: boolean;
|
|
3
|
+
canHide: boolean;
|
|
4
|
+
canManageLivestream: boolean;
|
|
5
|
+
isOwner: boolean;
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Hook to check if the current user can moderate for a given streamer.
|
|
11
|
+
* Returns permission flags based on:
|
|
12
|
+
* - Owner: full permissions if userDID === streamerDID
|
|
13
|
+
* - Delegated: permissions from place.stream.moderation.permission records
|
|
14
|
+
*/
|
|
15
|
+
export declare function useCanModerate(streamerDID: string | null | undefined): ModerationPermissions;
|
|
16
|
+
//# sourceMappingURL=moderation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moderation.d.ts","sourceRoot":"","sources":["../../src/streamplace-store/moderation.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,qBAAqB,CAkKvB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useCanModerate = useCanModerate;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const livestream_store_1 = require("../livestream-store/livestream-store");
|
|
6
|
+
const xrpc_1 = require("./xrpc");
|
|
7
|
+
/**
|
|
8
|
+
* Hook to check if the current user can moderate for a given streamer.
|
|
9
|
+
* Returns permission flags based on:
|
|
10
|
+
* - Owner: full permissions if userDID === streamerDID
|
|
11
|
+
* - Delegated: permissions from place.stream.moderation.permission records
|
|
12
|
+
*/
|
|
13
|
+
function useCanModerate(streamerDID) {
|
|
14
|
+
const agent = (0, xrpc_1.usePDSAgent)();
|
|
15
|
+
const userDID = agent?.did;
|
|
16
|
+
// Get moderation permissions from livestream store (updated via WebSocket)
|
|
17
|
+
const moderationPermissions = (0, livestream_store_1.useLivestreamStore)((state) => state.moderationPermissions);
|
|
18
|
+
const setModerationPermissions = (0, livestream_store_1.useLivestreamStore)((state) => state.setModerationPermissions);
|
|
19
|
+
const [isOwner, setIsOwner] = (0, react_1.useState)(false);
|
|
20
|
+
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
21
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
22
|
+
(0, react_1.useEffect)(() => {
|
|
23
|
+
if (!userDID || !streamerDID) {
|
|
24
|
+
setModerationPermissions([]);
|
|
25
|
+
setIsOwner(false);
|
|
26
|
+
setError(null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// If user is the streamer, they have full permissions
|
|
30
|
+
if (userDID === streamerDID) {
|
|
31
|
+
setIsOwner(true);
|
|
32
|
+
setModerationPermissions([]); // Not needed for owner
|
|
33
|
+
setIsLoading(false);
|
|
34
|
+
setError(null);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Otherwise, fetch delegation records from the streamer's repo
|
|
38
|
+
// This initial fetch populates the store, then WebSocket updates will keep it in sync
|
|
39
|
+
const fetchDelegation = async () => {
|
|
40
|
+
if (!agent) {
|
|
41
|
+
setModerationPermissions([]);
|
|
42
|
+
setIsLoading(false);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setIsLoading(true);
|
|
46
|
+
setError(null);
|
|
47
|
+
setIsOwner(false);
|
|
48
|
+
try {
|
|
49
|
+
// Use authenticated agent to list permission records from the streamer's repo
|
|
50
|
+
const result = await agent.com.atproto.repo.listRecords({
|
|
51
|
+
repo: streamerDID,
|
|
52
|
+
collection: "place.stream.moderation.permission",
|
|
53
|
+
limit: 100,
|
|
54
|
+
});
|
|
55
|
+
const records = result.data.records || [];
|
|
56
|
+
const permissionRecords = records
|
|
57
|
+
.map((r) => r.value)
|
|
58
|
+
.filter((v) => v && v.$type === "place.stream.moderation.permission");
|
|
59
|
+
// Store all permissions in the livestream store
|
|
60
|
+
// WebSocket updates will keep this in sync
|
|
61
|
+
setModerationPermissions(permissionRecords);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
console.error("[useCanModerate] Error fetching permissions:", err);
|
|
65
|
+
setError(`Could not fetch moderation permissions: ${err instanceof Error ? err.message : `Unknown error: ${err}`}`);
|
|
66
|
+
setModerationPermissions([]);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
setIsLoading(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
// Fetch immediately on mount or when dependencies change
|
|
73
|
+
fetchDelegation();
|
|
74
|
+
}, [userDID, streamerDID, agent, setModerationPermissions]);
|
|
75
|
+
// If permissions were cleared (e.g., due to deletion), trigger a refetch
|
|
76
|
+
(0, react_1.useEffect)(() => {
|
|
77
|
+
// If permissions were cleared and we're not the owner, refetch
|
|
78
|
+
if (moderationPermissions.length === 0 &&
|
|
79
|
+
!isOwner &&
|
|
80
|
+
userDID &&
|
|
81
|
+
streamerDID &&
|
|
82
|
+
agent) {
|
|
83
|
+
const fetchDelegation = async () => {
|
|
84
|
+
try {
|
|
85
|
+
const result = await agent.com.atproto.repo.listRecords({
|
|
86
|
+
repo: streamerDID,
|
|
87
|
+
collection: "place.stream.moderation.permission",
|
|
88
|
+
limit: 100,
|
|
89
|
+
});
|
|
90
|
+
const records = result.data.records || [];
|
|
91
|
+
const permissionRecords = records
|
|
92
|
+
.map((r) => r.value)
|
|
93
|
+
.filter((v) => v && v.$type === "place.stream.moderation.permission");
|
|
94
|
+
setModerationPermissions(permissionRecords);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.error("[useCanModerate] Error refetching permissions:", err);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
// Small delay to avoid rapid refetches
|
|
101
|
+
const timeout = setTimeout(fetchDelegation, 100);
|
|
102
|
+
return () => clearTimeout(timeout);
|
|
103
|
+
}
|
|
104
|
+
}, [
|
|
105
|
+
moderationPermissions.length,
|
|
106
|
+
isOwner,
|
|
107
|
+
userDID,
|
|
108
|
+
streamerDID,
|
|
109
|
+
agent,
|
|
110
|
+
setModerationPermissions,
|
|
111
|
+
]);
|
|
112
|
+
// Find ALL delegation records for this moderator and merge their permissions
|
|
113
|
+
const delegations = moderationPermissions.filter((perm) => perm.moderator === userDID);
|
|
114
|
+
// Merge permissions from all delegation records for this moderator
|
|
115
|
+
const permissions = delegations.reduce((acc, delegation) => {
|
|
116
|
+
// Check if delegation has expired
|
|
117
|
+
if (delegation.expirationTime) {
|
|
118
|
+
const expiration = new Date(delegation.expirationTime);
|
|
119
|
+
if (new Date() > expiration) {
|
|
120
|
+
return acc; // Skip expired delegations
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Add all permissions from this delegation, avoiding duplicates
|
|
124
|
+
const delegationPerms = delegation.permissions || [];
|
|
125
|
+
for (const perm of delegationPerms) {
|
|
126
|
+
if (!acc.includes(perm)) {
|
|
127
|
+
acc.push(perm);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return acc;
|
|
131
|
+
}, []);
|
|
132
|
+
return {
|
|
133
|
+
canBan: isOwner || permissions.includes("ban"),
|
|
134
|
+
canHide: isOwner || permissions.includes("hide"),
|
|
135
|
+
canManageLivestream: isOwner || permissions.includes("livestream.manage"),
|
|
136
|
+
isOwner,
|
|
137
|
+
isLoading,
|
|
138
|
+
error,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=moderation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moderation.js","sourceRoot":"","sources":["../../src/streamplace-store/moderation.tsx"],"names":[],"mappings":"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"}
|