@piedata/pieui 1.0.1 → 1.1.1
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/cli.js +11 -9
- package/dist/components/Buttons/AjaxButtonCard/ui/AjaxButtonCard.d.ts +2 -2
- package/dist/components/Buttons/AjaxButtonCard/ui/AjaxButtonCard.d.ts.map +1 -1
- package/dist/components/Chats/ChatCard/ui/components/AttachFileButton.d.ts.map +1 -1
- package/dist/components/Chats/ChatCard/ui/components/ChatCardInput.d.ts +1 -0
- package/dist/components/Chats/ChatCard/ui/components/ChatCardInput.d.ts.map +1 -1
- package/dist/components/Chats/ChatCard/ui/components/Markdown.d.ts +0 -1
- package/dist/components/Chats/ChatCard/ui/components/Markdown.d.ts.map +1 -1
- package/dist/components/Containers/AjaxGroupCard/ui/AjaxGroupCard.d.ts +2 -2
- package/dist/components/Containers/AjaxGroupCard/ui/AjaxGroupCard.d.ts.map +1 -1
- package/dist/components/Containers/SequenceCard/ui/SequenceCard.d.ts.map +1 -1
- package/dist/components/Containers/UnionCard/ui/UnionCard.d.ts.map +1 -1
- package/dist/components/PieCard/index.d.ts.map +1 -1
- package/dist/components/PieRoot/index.d.ts +1 -2
- package/dist/components/PieRoot/index.d.ts.map +1 -1
- package/dist/components/PieRoot/types/index.d.ts +3 -0
- package/dist/components/PieRoot/types/index.d.ts.map +1 -1
- package/dist/components/PieTelegramRoot/index.d.ts.map +1 -1
- package/dist/components/UI/index.d.ts.map +1 -1
- package/dist/components/index.esm.js +24 -26
- package/dist/components/index.js +33 -36
- package/dist/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +30 -32
- package/dist/index.js +43 -46
- package/dist/providers/CentrifugeIOInitProvider.d.ts.map +1 -1
- package/dist/providers/SocketIOInitProvider.d.ts.map +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/util/ajaxCommonUtils.d.ts.map +1 -1
- package/dist/util/centrifuge.d.ts +1 -1
- package/dist/util/centrifuge.d.ts.map +1 -1
- package/dist/util/initializeComponents.d.ts.map +1 -1
- package/dist/util/pieConfig.d.ts +12 -0
- package/dist/util/pieConfig.d.ts.map +1 -0
- package/dist/util/registry.d.ts.map +1 -1
- package/dist/util/socket.d.ts +1 -1
- package/dist/util/socket.d.ts.map +1 -1
- package/dist/util/useIsSupported.d.ts +1 -1
- package/dist/util/useIsSupported.d.ts.map +1 -1
- package/dist/util/useWebApp.d.ts +2 -2
- package/dist/util/useWebApp.d.ts.map +1 -1
- package/dist/util/waitForSidAvailable.d.ts +1 -2
- package/dist/util/waitForSidAvailable.d.ts.map +1 -1
- package/dist/util/webrtcClient.d.ts.map +1 -1
- package/package.json +22 -18
- package/src/components/Buttons/AjaxButtonCard/index.ts +1 -0
- package/src/components/Buttons/AjaxButtonCard/types/index.ts +17 -0
- package/src/components/Buttons/AjaxButtonCard/ui/AjaxButtonCard.tsx +38 -0
- package/src/components/Chats/ChatCard/index.ts +1 -0
- package/src/components/Chats/ChatCard/types/annyang.d.ts +11 -0
- package/src/components/Chats/ChatCard/types/index.ts +59 -0
- package/src/components/Chats/ChatCard/ui/ChatCard.tsx +130 -0
- package/src/components/Chats/ChatCard/ui/components/AttachFileButton.tsx +48 -0
- package/src/components/Chats/ChatCard/ui/components/AttachedFileView.tsx +29 -0
- package/src/components/Chats/ChatCard/ui/components/ChatCardInput.tsx +177 -0
- package/src/components/Chats/ChatCard/ui/components/ChatOption.tsx +25 -0
- package/src/components/Chats/ChatCard/ui/components/Markdown.tsx +21 -0
- package/src/components/Chats/ChatCard/ui/components/MessageAvatar.tsx +17 -0
- package/src/components/Chats/ChatCard/ui/components/MessageCard.tsx +80 -0
- package/src/components/Chats/ChatCard/ui/components/MessageContent.tsx +27 -0
- package/src/components/Chats/ChatCard/ui/components/MessagesBoard.tsx +61 -0
- package/src/components/Chats/ChatCard/ui/components/Options.tsx +20 -0
- package/src/components/Chats/ChatCard/ui/components/ResizableTextarea.tsx +59 -0
- package/src/components/Chats/ChatCard/ui/components/SendButton.tsx +37 -0
- package/src/components/Chats/ChatCard/ui/components/VoiceListeningButton.tsx +35 -0
- package/src/components/Chats/ChatCard/ui/components/icons/AttachFileIcon.tsx +18 -0
- package/src/components/Chats/ChatCard/ui/components/icons/AttachedFileIcon.tsx +18 -0
- package/src/components/Chats/ChatCard/ui/components/icons/CancelFileIcon.tsx +14 -0
- package/src/components/Chats/ChatCard/ui/components/icons/DefaultAvatar.tsx +10 -0
- package/src/components/Chats/ChatCard/ui/components/icons/SendIcon.tsx +18 -0
- package/src/components/Chats/ChatCard/ui/components/icons/VoiceRecordIcon.tsx +15 -0
- package/src/components/Containers/AjaxGroupCard/index.ts +1 -0
- package/src/components/Containers/AjaxGroupCard/types/index.ts +17 -0
- package/src/components/Containers/AjaxGroupCard/ui/AjaxGroupCard.tsx +96 -0
- package/src/components/Containers/SequenceCard/index.ts +1 -0
- package/src/components/Containers/SequenceCard/types/index.ts +10 -0
- package/src/components/Containers/SequenceCard/ui/SequenceCard.tsx +32 -0
- package/src/components/Containers/UnionCard/index.ts +1 -0
- package/src/components/Containers/UnionCard/types/index.ts +8 -0
- package/src/components/Containers/UnionCard/ui/UnionCard.tsx +27 -0
- package/src/components/PieCard/index.tsx +149 -0
- package/src/components/PieCard/types/index.ts +18 -0
- package/src/components/PieRoot/index.tsx +154 -0
- package/src/components/PieRoot/types/index.ts +14 -0
- package/src/components/PieTelegramRoot/index.tsx +161 -0
- package/src/components/UI/index.tsx +70 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +15 -0
- package/src/providers/CentrifugeIOInitProvider.tsx +42 -0
- package/src/providers/SocketIOInitProvider.tsx +52 -0
- package/src/types/index.ts +139 -0
- package/src/util/ajaxCommonUtils.ts +137 -0
- package/src/util/centrifuge.ts +33 -0
- package/src/util/fallback.tsx +6 -0
- package/src/util/initializeComponents.ts +84 -0
- package/src/util/lazy.ts +25 -0
- package/src/util/mitt.ts +11 -0
- package/src/util/pieConfig.ts +43 -0
- package/src/util/registry.ts +81 -0
- package/src/util/socket.ts +24 -0
- package/src/util/sx2radium.ts +15 -0
- package/src/util/tailwindCommonUtils.ts +6 -0
- package/src/util/useIsSupported.ts +17 -0
- package/src/util/useOpenAIWebRTC.ts +176 -0
- package/src/util/useWebApp.ts +32 -0
- package/src/util/waitForSidAvailable.ts +21 -0
- package/src/util/webrtcClient.ts +247 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/components/PieBaseRoot/index.d.ts +0 -5
- package/dist/components/PieBaseRoot/index.d.ts.map +0 -1
- package/dist/components/PieBaseRoot/types/index.d.ts +0 -6
- package/dist/components/PieBaseRoot/types/index.d.ts.map +0 -1
- package/dist/components/PieStaticRoot/index.d.ts +0 -5
- package/dist/components/PieStaticRoot/index.d.ts.map +0 -1
- package/dist/components/PieStaticRoot/types/index.d.ts +0 -7
- package/dist/components/PieStaticRoot/types/index.d.ts.map +0 -1
- package/dist/config/constant.d.ts +0 -10
- package/dist/config/constant.d.ts.map +0 -1
- package/dist/util/axiosWithCache.d.ts +0 -3
- package/dist/util/axiosWithCache.d.ts.map +0 -1
- package/dist/util/globalForm.d.ts +0 -3
- package/dist/util/globalForm.d.ts.map +0 -1
- package/dist/util/queryClient.d.ts +0 -3
- package/dist/util/queryClient.d.ts.map +0 -1
- package/dist/util/useBodyStyles.d.ts +0 -5
- package/dist/util/useBodyStyles.d.ts.map +0 -1
- package/dist/util/useImage.d.ts +0 -5
- package/dist/util/useImage.d.ts.map +0 -1
- package/dist/util/useScreenSize.d.ts +0 -6
- package/dist/util/useScreenSize.d.ts.map +0 -1
- package/dist/util/useTitle.d.ts +0 -2
- package/dist/util/useTitle.d.ts.map +0 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import React, {useEffect, useMemo} from 'react'
|
|
2
|
+
import {QueryClient, QueryClientProvider, useQuery} from '@tanstack/react-query'
|
|
3
|
+
|
|
4
|
+
import Radium from "radium";
|
|
5
|
+
import {PieRootProps} from '../PieRoot/types'
|
|
6
|
+
|
|
7
|
+
import MittContext, {emitter} from "../../util/mitt"
|
|
8
|
+
import SocketIOContext, {getSocket} from "../../util/socket"
|
|
9
|
+
import CentrifugeIOContext, {getCentrifuge} from "../../util/centrifuge"
|
|
10
|
+
|
|
11
|
+
import SocketIOInitProvider from "../../providers/SocketIOInitProvider"
|
|
12
|
+
import CentrifugeIOInitProvider from "../../providers/CentrifugeIOInitProvider"
|
|
13
|
+
import FallbackContext from "../../util/fallback";
|
|
14
|
+
import {UIConfigType} from "../../types";
|
|
15
|
+
import {AxiosError} from "axios";
|
|
16
|
+
import UI from "../UI";
|
|
17
|
+
import { createAxiosDateTransformer } from "axios-date-transformer";
|
|
18
|
+
import {
|
|
19
|
+
getApiServer,
|
|
20
|
+
isRenderingLogEnabled,
|
|
21
|
+
getCentrifugeServer,
|
|
22
|
+
PieConfigContext
|
|
23
|
+
} from "../../util/pieConfig";
|
|
24
|
+
import {initializePieComponents, isPieComponentsInitialized} from "../../util/initializeComponents.ts";
|
|
25
|
+
import {useWebApp} from "../../util/useWebApp.ts";
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const PieTelegramRootContent: React.FC<PieRootProps> = ({ location, fallback, onError, initializePie }) => {
|
|
29
|
+
const apiServer = getApiServer()
|
|
30
|
+
const centrifugeServer = getCentrifugeServer()
|
|
31
|
+
const renderingLogEnabled = isRenderingLogEnabled()
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (isPieComponentsInitialized()) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
initializePieComponents()
|
|
38
|
+
initializePie()
|
|
39
|
+
}, [])
|
|
40
|
+
|
|
41
|
+
const axiosInstance = useMemo(() => createAxiosDateTransformer({
|
|
42
|
+
baseURL: apiServer,
|
|
43
|
+
}), [])
|
|
44
|
+
|
|
45
|
+
if (renderingLogEnabled) {
|
|
46
|
+
console.log('[PieRoot] Rendering with location:', location)
|
|
47
|
+
console.log('[PieRoot] API_SERVER:', apiServer)
|
|
48
|
+
console.log('[PieRoot] Fallback provided:', !!fallback)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!apiServer) {
|
|
52
|
+
throw Error("Set PIE_API_SERVER and PIE_CENTRIFUGE_SERVER")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// if (!isPieComponentsInitialized()) {
|
|
56
|
+
// throw Error("Pie components are not initialized. Use initializePieComponents() at the top of page file")
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
const webApp = useWebApp()
|
|
60
|
+
|
|
61
|
+
const {
|
|
62
|
+
data: uiConfiguration,
|
|
63
|
+
isLoading,
|
|
64
|
+
error,
|
|
65
|
+
} = useQuery<UIConfigType, AxiosError>({
|
|
66
|
+
queryKey: ['uiConfig', location.pathname + location.search, webApp?.initData, isPieComponentsInitialized()],
|
|
67
|
+
queryFn: async () => {
|
|
68
|
+
if (!isPieComponentsInitialized()) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
const querySymbol = location.search ? '&' : '?'
|
|
72
|
+
const initData = webApp?.initData
|
|
73
|
+
? `${querySymbol}initData=${encodeURIComponent(webApp.initData)}`
|
|
74
|
+
: ''
|
|
75
|
+
const apiEndpoint = '/api/content' + location.pathname + location.search + initData
|
|
76
|
+
|
|
77
|
+
if (renderingLogEnabled) {
|
|
78
|
+
console.log('[PieRoot] Fetching UI configuration from:', apiEndpoint)
|
|
79
|
+
}
|
|
80
|
+
const response = await axiosInstance.get(apiEndpoint, {
|
|
81
|
+
headers: {
|
|
82
|
+
'Access-Control-Allow-Origin': '*',
|
|
83
|
+
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
|
|
84
|
+
'Content-type': 'application/json',
|
|
85
|
+
},
|
|
86
|
+
withCredentials: true,
|
|
87
|
+
})
|
|
88
|
+
if (renderingLogEnabled) {
|
|
89
|
+
console.log('[PieRoot] Received UI configuration:', response.data)
|
|
90
|
+
}
|
|
91
|
+
return response.data
|
|
92
|
+
},
|
|
93
|
+
staleTime: Infinity,
|
|
94
|
+
gcTime: Infinity,
|
|
95
|
+
refetchOnWindowFocus: false,
|
|
96
|
+
refetchOnMount: false,
|
|
97
|
+
refetchOnReconnect: false,
|
|
98
|
+
retry: true,
|
|
99
|
+
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (error && renderingLogEnabled) {
|
|
103
|
+
console.error('[PieRoot] Error fetching UI configuration:', error)
|
|
104
|
+
console.error('[PieRoot] Error details:', {
|
|
105
|
+
message: error.message,
|
|
106
|
+
status: error.response?.status,
|
|
107
|
+
data: error.response?.data
|
|
108
|
+
})
|
|
109
|
+
onError?.()
|
|
110
|
+
return fallback
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if (isLoading || !uiConfiguration) {
|
|
115
|
+
if (renderingLogEnabled) {
|
|
116
|
+
console.log('[PieRoot] Loading state:', { isLoading, hasUiConfiguration: !!uiConfiguration })
|
|
117
|
+
}
|
|
118
|
+
return fallback
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (renderingLogEnabled) {
|
|
122
|
+
console.log('[PieRoot] UI configuration loaded successfully:', uiConfiguration)
|
|
123
|
+
console.log('[PieRoot] Rendering UI with configuration')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<MittContext.Provider value={emitter}>
|
|
128
|
+
<SocketIOContext.Provider value={getSocket(apiServer)}>
|
|
129
|
+
<CentrifugeIOContext.Provider value={getCentrifuge(apiServer, centrifugeServer)}>
|
|
130
|
+
<FallbackContext.Provider value={fallback ?? <></>}>
|
|
131
|
+
<SocketIOInitProvider>
|
|
132
|
+
<CentrifugeIOInitProvider>
|
|
133
|
+
|
|
134
|
+
<Radium.StyleRoot>
|
|
135
|
+
<UI uiConfig={uiConfiguration} />
|
|
136
|
+
</Radium.StyleRoot>
|
|
137
|
+
|
|
138
|
+
</CentrifugeIOInitProvider>
|
|
139
|
+
</SocketIOInitProvider>
|
|
140
|
+
</FallbackContext.Provider>
|
|
141
|
+
</CentrifugeIOContext.Provider>
|
|
142
|
+
</SocketIOContext.Provider>
|
|
143
|
+
</MittContext.Provider>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
const PieTelegramRoot: React.FC<PieRootProps> = (props) => {
|
|
150
|
+
const queryClient = new QueryClient()
|
|
151
|
+
return (
|
|
152
|
+
<PieConfigContext.Provider value={props.config}>
|
|
153
|
+
<QueryClientProvider client={queryClient}>
|
|
154
|
+
<PieTelegramRootContent {...props} />
|
|
155
|
+
</QueryClientProvider>
|
|
156
|
+
</PieConfigContext.Provider>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
export default PieTelegramRoot
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { UIConfigType, SetUiAjaxConfigurationType } from '../../types'
|
|
2
|
+
import { getRegistryEntry } from "../../util/registry";
|
|
3
|
+
import {Suspense, useContext, ReactNode} from "react";
|
|
4
|
+
import FallbackContext from "../../util/fallback";
|
|
5
|
+
import { isRenderingLogEnabled } from '../../util/pieConfig';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function UI({
|
|
9
|
+
uiConfig,
|
|
10
|
+
setUiAjaxConfiguration,
|
|
11
|
+
}: {
|
|
12
|
+
uiConfig: UIConfigType
|
|
13
|
+
setUiAjaxConfiguration?: SetUiAjaxConfigurationType
|
|
14
|
+
}) {
|
|
15
|
+
const Fallback: ReactNode = useContext(FallbackContext)
|
|
16
|
+
const renderingLogEnabled = isRenderingLogEnabled()
|
|
17
|
+
|
|
18
|
+
if (renderingLogEnabled) {
|
|
19
|
+
console.log('[UI] Rendering component:', uiConfig.card)
|
|
20
|
+
console.log('[UI] Component data:', uiConfig.data)
|
|
21
|
+
console.log('[UI] Component content:', uiConfig.content)
|
|
22
|
+
console.log('[UI] Has setUiAjaxConfiguration:', !!setUiAjaxConfiguration)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const entry = getRegistryEntry(uiConfig.card)
|
|
26
|
+
if (!entry?.component) {
|
|
27
|
+
if (renderingLogEnabled) {
|
|
28
|
+
console.warn(`[UI] Component not found in registry: ${uiConfig.card}`)
|
|
29
|
+
console.log('[UI] Returning fallback component')
|
|
30
|
+
}
|
|
31
|
+
return Fallback
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (renderingLogEnabled) {
|
|
35
|
+
console.log('[UI] Found component in registry:', {
|
|
36
|
+
name: entry.name,
|
|
37
|
+
isLazy: entry.isLazy,
|
|
38
|
+
hasMetadata: !!entry.metadata
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const Component = entry.component
|
|
43
|
+
|
|
44
|
+
const node = (
|
|
45
|
+
<Component
|
|
46
|
+
data={uiConfig.data}
|
|
47
|
+
content={uiConfig.content}
|
|
48
|
+
setUiAjaxConfiguration={setUiAjaxConfiguration}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if (entry.isLazy) {
|
|
53
|
+
if (renderingLogEnabled) {
|
|
54
|
+
console.log('[UI] Rendering lazy component with Suspense:', entry.name)
|
|
55
|
+
}
|
|
56
|
+
return (
|
|
57
|
+
<Suspense key={`${entry.name}`} fallback={entry.fallback ?? Fallback}>
|
|
58
|
+
{node}
|
|
59
|
+
</Suspense>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (renderingLogEnabled) {
|
|
64
|
+
console.log('[UI] Rendering component directly:', entry.name)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return node
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default UI
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as PieCard } from './PieCard';
|
|
2
|
+
export { default as UI } from './UI';
|
|
3
|
+
export { default as ChatCard } from './Chats/ChatCard';
|
|
4
|
+
export { default as AjaxButtonCard } from './Buttons/AjaxButtonCard'
|
|
5
|
+
export { default as SequenceCard } from './Containers/SequenceCard'
|
|
6
|
+
export { default as UnionCard } from './Containers/UnionCard'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { default as UI } from './components/UI'
|
|
2
|
+
export { default as PieRoot } from './components/PieRoot'
|
|
3
|
+
export { default as PieTelegramRoot } from './components/PieTelegramRoot'
|
|
4
|
+
export { default as PieCard } from './components/PieCard'
|
|
5
|
+
export { registerPieComponent } from './util/registry'
|
|
6
|
+
export { initializePieComponents, isPieComponentsInitialized } from './util/initializeComponents'
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
PieSimpleComponentProps,
|
|
10
|
+
PieComplexComponentProps,
|
|
11
|
+
PieContainerComponentProps,
|
|
12
|
+
PieComplexContainerComponentProps,
|
|
13
|
+
PieConfig
|
|
14
|
+
} from './types'
|
|
15
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ReactNode, useContext, useEffect } from 'react'
|
|
2
|
+
import CentrifugeIOContext from '../util/centrifuge'
|
|
3
|
+
import { useIsSupported } from '../util/useIsSupported'
|
|
4
|
+
import { getApiServer } from "../util/pieConfig";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const CentrifugeIOInitProvider = ({ children }: { children: ReactNode }) => {
|
|
8
|
+
const centrifuge = useContext(CentrifugeIOContext)
|
|
9
|
+
const apiServer = getApiServer()
|
|
10
|
+
|
|
11
|
+
const isCentrifugeSupported = useIsSupported(apiServer, 'centrifuge')
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!centrifuge) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const onConnectEvent = () => {
|
|
19
|
+
console.log('Centrifuge connected')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const onDisconnectEvent = (event: any) => {
|
|
23
|
+
console.log(`Centrifuge disconnected:`, event)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (isCentrifugeSupported) {
|
|
27
|
+
centrifuge.on('connected', onConnectEvent)
|
|
28
|
+
centrifuge.on('disconnected', onDisconnectEvent)
|
|
29
|
+
centrifuge.connect()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
if (isCentrifugeSupported) {
|
|
34
|
+
centrifuge.disconnect()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, [centrifuge, isCentrifugeSupported])
|
|
38
|
+
|
|
39
|
+
return children
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default CentrifugeIOInitProvider
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ReactNode, useContext, useEffect } from 'react'
|
|
2
|
+
import SocketIOContext from '../util/socket'
|
|
3
|
+
import { useIsSupported } from '../util/useIsSupported'
|
|
4
|
+
import { Socket } from 'socket.io-client'
|
|
5
|
+
import { getApiServer } from "../util/pieConfig";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const SocketIOInitProvider = ({ children }: { children: ReactNode }) => {
|
|
9
|
+
const socket: Socket | null = useContext(SocketIOContext)
|
|
10
|
+
const apiServer = getApiServer()
|
|
11
|
+
const isSocketIOSupported = useIsSupported(apiServer, 'socketIO')
|
|
12
|
+
|
|
13
|
+
const onPieInitEvent = (event: any) => {
|
|
14
|
+
if (typeof window !== 'undefined') {
|
|
15
|
+
window.sid = event.sid
|
|
16
|
+
console.log(`SocketIO initialized: ${window.sid}`)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!socket) {
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
const onConnectEvent = () => {
|
|
25
|
+
console.log('SocketIO connected')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const onDisconnectEvent = (event: any) => {
|
|
29
|
+
console.log(`SocketIO disconnected: ${event}`)
|
|
30
|
+
socket.connect()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (isSocketIOSupported) {
|
|
34
|
+
socket.on(`pieinit`, onPieInitEvent)
|
|
35
|
+
socket.on('connect', onConnectEvent)
|
|
36
|
+
socket.on('disconnect', onDisconnectEvent)
|
|
37
|
+
socket.connect()
|
|
38
|
+
}
|
|
39
|
+
return () => {
|
|
40
|
+
if (isSocketIOSupported) {
|
|
41
|
+
socket.off(`pieinit`, onPieInitEvent)
|
|
42
|
+
socket.off('connect', onConnectEvent)
|
|
43
|
+
socket.off('disconnect', onDisconnectEvent)
|
|
44
|
+
socket.disconnect()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}, [socket, isSocketIOSupported])
|
|
48
|
+
|
|
49
|
+
return children
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default SocketIOInitProvider
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {ComponentType, ReactNode} from "react";
|
|
2
|
+
|
|
3
|
+
export type WebAppUser = {
|
|
4
|
+
id: string
|
|
5
|
+
username: string
|
|
6
|
+
photo_url: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type MainButtonType = {
|
|
10
|
+
show: () => void
|
|
11
|
+
onClick: (callback: () => void) => void
|
|
12
|
+
offClick: (callback: () => void) => void
|
|
13
|
+
setText: (text: string) => void
|
|
14
|
+
hide: () => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type BackButtonType = {
|
|
18
|
+
show: () => void
|
|
19
|
+
onClick: (callback: () => void) => void
|
|
20
|
+
hide: () => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type WebAppInitData = {
|
|
24
|
+
user: WebAppUser
|
|
25
|
+
start_param?: string
|
|
26
|
+
chat_type?: 'sender' | 'private' | 'group' | 'supergroup' | 'channel'
|
|
27
|
+
chat_instance?: string
|
|
28
|
+
auth_date: number
|
|
29
|
+
hash: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type WebApp = {
|
|
33
|
+
sendData: (data: string) => void
|
|
34
|
+
showAlert: (message: string) => void
|
|
35
|
+
MainButton: MainButtonType
|
|
36
|
+
BackButton: BackButtonType
|
|
37
|
+
initDataUnsafe: WebAppInitData
|
|
38
|
+
initData: string
|
|
39
|
+
ready: () => void
|
|
40
|
+
close: () => void
|
|
41
|
+
openLink: (link: string, option: string) => void
|
|
42
|
+
platform: 'ios' | 'android' | 'web'
|
|
43
|
+
expand: () => void
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type Telegram = {
|
|
47
|
+
WebApp: WebApp
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type InitDataUnsafe = {
|
|
51
|
+
user?: WebAppUser
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type InitData = string
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
export interface UIConfigType {
|
|
58
|
+
card: string
|
|
59
|
+
data: any
|
|
60
|
+
content: UIConfigType | Array<UIConfigType>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface UIEventType {
|
|
64
|
+
name: string
|
|
65
|
+
data: Record<any, any>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type SetUiAjaxConfigurationType =
|
|
69
|
+
| ((content: UIConfigType | null) => void)
|
|
70
|
+
| ((events: Array<UIEventType> | null) => void)
|
|
71
|
+
|
|
72
|
+
export interface PieEvent {
|
|
73
|
+
cardName: string
|
|
74
|
+
name: string
|
|
75
|
+
eventName: string
|
|
76
|
+
data: any
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type PieEventEmitter = (event: PieEvent) => void
|
|
80
|
+
|
|
81
|
+
declare global {
|
|
82
|
+
interface Window {
|
|
83
|
+
sid: string
|
|
84
|
+
Telegram: Telegram
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
export interface ComponentMetadata {
|
|
90
|
+
author?: string
|
|
91
|
+
version?: string
|
|
92
|
+
description?: string
|
|
93
|
+
tags?: string[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export interface PieComplexContainerComponentProps<TData = unknown> {
|
|
98
|
+
data: TData
|
|
99
|
+
content: Array<UIConfigType>
|
|
100
|
+
setUiAjaxConfiguration?: SetUiAjaxConfigurationType
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface PieContainerComponentProps<TData = unknown> {
|
|
104
|
+
data: TData
|
|
105
|
+
content: UIConfigType
|
|
106
|
+
setUiAjaxConfiguration?: SetUiAjaxConfigurationType
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface PieComplexComponentProps<TData = unknown> {
|
|
110
|
+
data: TData
|
|
111
|
+
setUiAjaxConfiguration?: SetUiAjaxConfigurationType
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface PieSimpleComponentProps<TData = unknown> {
|
|
115
|
+
data: TData
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type PieComponentProps<TData = unknown> =
|
|
119
|
+
| PieSimpleComponentProps<TData>
|
|
120
|
+
| PieContainerComponentProps<TData>
|
|
121
|
+
| PieComplexContainerComponentProps<TData>
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
export interface ComponentRegistration<TProps> {
|
|
125
|
+
name: string
|
|
126
|
+
component?: ComponentType<TProps>
|
|
127
|
+
fallback?: ReactNode
|
|
128
|
+
loader?: () => Promise<{ default: ComponentType<TProps> }>
|
|
129
|
+
metadata?: ComponentMetadata
|
|
130
|
+
isLazy?: boolean
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
export interface PieConfig {
|
|
135
|
+
apiServer: string
|
|
136
|
+
centrifugeServer?: string
|
|
137
|
+
enableRenderingLog?: boolean
|
|
138
|
+
pageProcessor?: string
|
|
139
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {getApiServer, isRenderingLogEnabled} from './pieConfig'
|
|
2
|
+
import '../types'
|
|
3
|
+
import { SetUiAjaxConfigurationType, UIEventType } from '../types'
|
|
4
|
+
import waitForSidAvailable from './waitForSidAvailable'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const getAjaxSubmit = (
|
|
8
|
+
setUiAjaxConfiguration?: SetUiAjaxConfigurationType,
|
|
9
|
+
kwargs: Record<string, any> = {},
|
|
10
|
+
depsNames: Array<string> = [],
|
|
11
|
+
pathname?: string,
|
|
12
|
+
) => {
|
|
13
|
+
const renderingLogEnabled = isRenderingLogEnabled()
|
|
14
|
+
|
|
15
|
+
if (renderingLogEnabled) {
|
|
16
|
+
console.log('Registering AJAX: ', pathname, kwargs, depsNames)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!pathname || !setUiAjaxConfiguration) {
|
|
20
|
+
if (renderingLogEnabled) {
|
|
21
|
+
console.warn('Registration FAILED: pathname or setUiAjaxConfiguration is missing!')
|
|
22
|
+
}
|
|
23
|
+
return () => {}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return async (extraKwargs: Record<string, any> = {}) => {
|
|
27
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
28
|
+
if (renderingLogEnabled) {
|
|
29
|
+
console.warn('getAjaxSubmit called on server, skipping DOM-dependent logic')
|
|
30
|
+
}
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (depsNames.includes('sid')) {
|
|
35
|
+
await waitForSidAvailable()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const data = new FormData()
|
|
39
|
+
for (const [key, value] of Object.entries({ ...kwargs, ...extraKwargs })) {
|
|
40
|
+
data.append(key, value)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const depName of depsNames) {
|
|
44
|
+
if (depName === 'sid') {
|
|
45
|
+
if (!window.sid) throw new Error("SocketIO isn't initialized properly")
|
|
46
|
+
data.append('sid', window.sid)
|
|
47
|
+
} else {
|
|
48
|
+
const inputs = document.getElementsByName(depName)
|
|
49
|
+
if (!inputs.length) {
|
|
50
|
+
if (renderingLogEnabled) {
|
|
51
|
+
console.warn(`No input found with name ${depName}`)
|
|
52
|
+
}
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
const input = inputs[0]
|
|
56
|
+
if (input instanceof HTMLInputElement) {
|
|
57
|
+
if (input.type === 'file' && input.files) {
|
|
58
|
+
Array.from(input.files).forEach((file) => data.append(depName, file))
|
|
59
|
+
} else {
|
|
60
|
+
data.append(depName, input.value)
|
|
61
|
+
}
|
|
62
|
+
} else if (input instanceof HTMLTextAreaElement) {
|
|
63
|
+
data.append(depName, input.value)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const apiEndpoint = getApiServer() + 'api/ajax_content' + pathname
|
|
69
|
+
|
|
70
|
+
setUiAjaxConfiguration(null)
|
|
71
|
+
return await fetch(apiEndpoint, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
body: data,
|
|
74
|
+
})
|
|
75
|
+
.then(async (response) => {
|
|
76
|
+
const contentType = response.headers.get('content-type') || ''
|
|
77
|
+
const isJson = contentType.includes('application/json')
|
|
78
|
+
const isStream = !!response.body?.getReader && !isJson
|
|
79
|
+
|
|
80
|
+
if (isStream) {
|
|
81
|
+
const reader = response.body!.getReader()
|
|
82
|
+
const decoder = new TextDecoder()
|
|
83
|
+
let buffer = ''
|
|
84
|
+
|
|
85
|
+
// eslint-disable-next-line no-constant-condition
|
|
86
|
+
while (true) {
|
|
87
|
+
const { done, value } = await reader.read()
|
|
88
|
+
if (done) break
|
|
89
|
+
buffer += decoder.decode(value, { stream: true })
|
|
90
|
+
|
|
91
|
+
const lines = buffer.split('\n')
|
|
92
|
+
buffer = lines.pop() ?? ''
|
|
93
|
+
|
|
94
|
+
for (const line of lines) {
|
|
95
|
+
const trimmed = line.trim()
|
|
96
|
+
if (!trimmed) continue
|
|
97
|
+
try {
|
|
98
|
+
const currentEvent = JSON.parse(trimmed) as UIEventType
|
|
99
|
+
;(setUiAjaxConfiguration as (events: UIEventType[]) => void)([
|
|
100
|
+
currentEvent,
|
|
101
|
+
])
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (renderingLogEnabled) {
|
|
104
|
+
console.warn('Failed to parse streamed line:', trimmed)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (buffer.trim()) {
|
|
111
|
+
try {
|
|
112
|
+
const currentEvent = JSON.parse(buffer) as UIEventType
|
|
113
|
+
;(setUiAjaxConfiguration as (events: UIEventType[]) => void)([
|
|
114
|
+
currentEvent,
|
|
115
|
+
])
|
|
116
|
+
} catch (err) {
|
|
117
|
+
if (renderingLogEnabled) {
|
|
118
|
+
console.warn('Failed to parse final streamed line:', buffer)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {}
|
|
123
|
+
} else {
|
|
124
|
+
const data = await response.json()
|
|
125
|
+
setUiAjaxConfiguration(data)
|
|
126
|
+
return data
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
.catch((err) => {
|
|
130
|
+
if (renderingLogEnabled) {
|
|
131
|
+
console.error('AJAX request failed:', err)
|
|
132
|
+
}
|
|
133
|
+
setUiAjaxConfiguration(null)
|
|
134
|
+
return err
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createContext } from 'react'
|
|
2
|
+
import { Centrifuge } from 'centrifuge'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const getCentrifuge = (apiServer: string, centrifugeServer?: string) => {
|
|
6
|
+
|
|
7
|
+
async function getToken() {
|
|
8
|
+
const res = await fetch(apiServer + 'api/centrifuge/gen_token')
|
|
9
|
+
if (!res.ok) {
|
|
10
|
+
if (res.status === 403) {
|
|
11
|
+
throw new Centrifuge.UnauthorizedError('Backend is not answering')
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`Unexpected status code ${res.status}`)
|
|
14
|
+
}
|
|
15
|
+
const data = await res.json()
|
|
16
|
+
return data.token
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return centrifugeServer ?
|
|
20
|
+
new Centrifuge(centrifugeServer || '', {
|
|
21
|
+
getToken,
|
|
22
|
+
}): null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// export const centrifuge =
|
|
27
|
+
// getCentrifugeServer() ?
|
|
28
|
+
// new Centrifuge(getCentrifugeServer() || '', {
|
|
29
|
+
// getToken,
|
|
30
|
+
// }): null
|
|
31
|
+
|
|
32
|
+
const CentrifugeIOContext = createContext<Centrifuge | null>(null)
|
|
33
|
+
export default CentrifugeIOContext
|