playsout-web-sdk 1.0.6 → 1.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +353 -369
- package/chunk-2GXDF6SL.js +2 -0
- package/chunk-5YDFNAVU.cjs +2 -0
- package/data/games.d.ts.map +1 -1
- package/index.cjs +1 -1
- package/index.global.js +18 -25
- package/index.iife.js +18 -25
- package/index.js +1 -1
- package/package.json +1 -1
- package/react/index.cjs +1 -1
- package/react/index.js +1 -1
- package/vue/index.cjs +1 -1
- package/vue/index.js +1 -1
- package/web-components/PlaysoutWidget.d.ts.map +1 -1
- package/web-components/index.cjs +0 -7
- package/web-components/index.js +0 -7
- package/chunk-NHFWJCNJ.cjs +0 -2
- package/chunk-XDBADNFW.js +0 -2
package/README.md
CHANGED
|
@@ -1,386 +1,370 @@
|
|
|
1
|
-
# Playsout Web SDK Integration Guide
|
|
2
|
-
|
|
3
|
-
Playsout Web SDK lets HTML, Vue 3, and React applications embed the Playsout game list widget. It also provides SDK initialization, platform login, login state, user information, locale switching
|
|
4
|
-
|
|
5
|
-
This guide is organized so that integrators can select their project type and use the corresponding code directly.
|
|
6
|
-
|
|
7
|
-
## Key Points
|
|
8
|
-
|
|
9
|
-
- `appId` is not required.
|
|
10
|
-
- Game details use iframe mode by default, so `detailMode` does not need to be provided.
|
|
11
|
-
- Persistent SDK image caching is currently disabled. Images use their online URLs directly.
|
|
12
|
-
- `user-points` seeds the widget's frontend gem balance. The SDK does not fetch or persist the balance through a backend.
|
|
1
|
+
# Playsout Web SDK Integration Guide
|
|
2
|
+
|
|
3
|
+
Playsout Web SDK lets HTML, Vue 3, and React applications embed the Playsout game list widget. It also provides SDK initialization, platform login, login state, user information, and locale switching.
|
|
4
|
+
|
|
5
|
+
This guide is organized so that integrators can select their project type and use the corresponding code directly.
|
|
6
|
+
|
|
7
|
+
## Key Points
|
|
8
|
+
|
|
9
|
+
- `appId` is not required.
|
|
10
|
+
- Game details use iframe mode by default, so `detailMode` does not need to be provided.
|
|
11
|
+
- Persistent SDK image caching is currently disabled. Images use their online URLs directly.
|
|
13
12
|
- In iframe detail mode, games can request simulated gem payment through the `privy-bridge` postMessage protocol.
|
|
14
|
-
- Vue 3 projects built with Vite must configure `isCustomElement`.
|
|
15
|
-
- React projects do not need Vue's `isCustomElement` configuration. Import `playsout-web-sdk/web-components` once instead.
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install playsout-web-sdk
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Choose an Integration
|
|
24
|
-
|
|
25
|
-
| Project type | Guide |
|
|
26
|
-
| --- | --- |
|
|
27
|
-
| HTML / IIFE | [HTML integration](#html-integration) |
|
|
28
|
-
| Vue 3 + Vite | [Vue 3 integration](#vue-3-integration) |
|
|
29
|
-
| React | [React integration](#react-integration) |
|
|
30
|
-
|
|
31
|
-
## Recommended Integration Flow
|
|
32
|
-
|
|
33
|
-
Use the following sequence when the application starts:
|
|
34
|
-
|
|
35
|
-
1. Initialize the SDK.
|
|
36
|
-
2. Read the current login state.
|
|
37
|
-
3. If the user is not logged in, call `Login()`.
|
|
38
|
-
4. Render `<playsout-widget>`.
|
|
39
|
-
5. Use `locale` to control the language
|
|
40
|
-
|
|
41
|
-
During initialization, the SDK checks the stored token and user information. `isLoggedIn` is `true` only when both are present. It uses a valid access token directly and tries the refresh endpoint when the access token has expired. If refresh is unavailable or fails, the SDK reuses the most recently saved Grab/Eros `Login()` parameters to re-login once. If that recovery also fails, it clears the local authentication state, emits `authExpired`, and rejects the operation. Do not use `getUserInfo()` as a startup gate. Call it only when a page explicitly needs fresh backend user data.
|
|
42
|
-
|
|
43
|
-
## Login Parameters
|
|
44
|
-
|
|
45
|
-
Grab and Eros use the same public login method:
|
|
46
|
-
|
|
47
|
-
```js
|
|
48
|
-
await Playsout.Login(params);
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Required parameters:
|
|
52
|
-
|
|
53
|
-
| Parameter | Description |
|
|
54
|
-
| --- | --- |
|
|
55
|
-
| `platform` | Platform identifier. Use `'grab'` or `'eros'`. |
|
|
56
|
-
| `platformUserId` | Unique user ID from the host platform. |
|
|
57
|
-
| `platformToken` | Any random non-empty string; there are no other requirements. |
|
|
58
|
-
| `username` | User display name. |
|
|
59
|
-
|
|
60
|
-
Example:
|
|
61
|
-
|
|
62
|
-
```js
|
|
63
|
-
await Playsout.Login({
|
|
64
|
-
platform: 'eros',
|
|
65
|
-
platformUserId: '10',
|
|
66
|
-
platformToken: 'random-string',
|
|
67
|
-
username: 'TestUser',
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
`platformToken` is required, but any random non-empty string is accepted.
|
|
72
|
-
|
|
73
|
-
## HTML Integration
|
|
74
|
-
|
|
75
|
-
Use this method for a page that does not use a Vue or React build setup.
|
|
76
|
-
|
|
77
|
-
Place the following code in `index.html`:
|
|
78
|
-
|
|
79
|
-
```html
|
|
80
|
-
<!doctype html>
|
|
81
|
-
<html lang="en">
|
|
82
|
-
<head>
|
|
83
|
-
<meta charset="UTF-8" />
|
|
84
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
85
|
-
<title>Playsout HTML Demo</title>
|
|
86
|
-
</head>
|
|
87
|
-
<body>
|
|
88
|
-
<div id="game-container"></div>
|
|
89
|
-
|
|
90
|
-
<script src="https://unpkg.com/playsout-web-sdk/index.iife.js"></script>
|
|
91
|
-
<script>
|
|
92
|
-
let loginPromise = null;
|
|
93
|
-
|
|
94
|
-
function login() {
|
|
95
|
-
if (!loginPromise) {
|
|
96
|
-
loginPromise = window.Playsout.Login({
|
|
97
|
-
platform: 'eros',
|
|
98
|
-
platformUserId: '10',
|
|
99
|
-
platformToken: 'random-string',
|
|
100
|
-
username: 'TestUser'
|
|
101
|
-
}).finally(function () {
|
|
102
|
-
loginPromise = null;
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return loginPromise;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function ensureLogin() {
|
|
110
|
-
if (!window.Playsout.isLoggedIn) {
|
|
111
|
-
return login();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async function bootstrap() {
|
|
116
|
-
await window.Playsout.init({ locale: 'en' });
|
|
117
|
-
|
|
118
|
-
await ensureLogin();
|
|
119
|
-
|
|
13
|
+
- Vue 3 projects built with Vite must configure `isCustomElement`.
|
|
14
|
+
- React projects do not need Vue's `isCustomElement` configuration. Import `playsout-web-sdk/web-components` once instead.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install playsout-web-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Choose an Integration
|
|
23
|
+
|
|
24
|
+
| Project type | Guide |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| HTML / IIFE | [HTML integration](#html-integration) |
|
|
27
|
+
| Vue 3 + Vite | [Vue 3 integration](#vue-3-integration) |
|
|
28
|
+
| React | [React integration](#react-integration) |
|
|
29
|
+
|
|
30
|
+
## Recommended Integration Flow
|
|
31
|
+
|
|
32
|
+
Use the following sequence when the application starts:
|
|
33
|
+
|
|
34
|
+
1. Initialize the SDK.
|
|
35
|
+
2. Read the current login state.
|
|
36
|
+
3. If the user is not logged in, call `Login()`.
|
|
37
|
+
4. Render `<playsout-widget>`.
|
|
38
|
+
5. Use `locale` to control the language.
|
|
39
|
+
|
|
40
|
+
During initialization, the SDK checks the stored token and user information. `isLoggedIn` is `true` only when both are present. It uses a valid access token directly and tries the refresh endpoint when the access token has expired. If refresh is unavailable or fails, the SDK reuses the most recently saved Grab/Eros `Login()` parameters to re-login once. If that recovery also fails, it clears the local authentication state, emits `authExpired`, and rejects the operation. Do not use `getUserInfo()` as a startup gate. Call it only when a page explicitly needs fresh backend user data.
|
|
41
|
+
|
|
42
|
+
## Login Parameters
|
|
43
|
+
|
|
44
|
+
Grab and Eros use the same public login method:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
await Playsout.Login(params);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Required parameters:
|
|
51
|
+
|
|
52
|
+
| Parameter | Description |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| `platform` | Platform identifier. Use `'grab'` or `'eros'`. |
|
|
55
|
+
| `platformUserId` | Unique user ID from the host platform. |
|
|
56
|
+
| `platformToken` | Any random non-empty string; there are no other requirements. |
|
|
57
|
+
| `username` | User display name. |
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
await Playsout.Login({
|
|
63
|
+
platform: 'eros',
|
|
64
|
+
platformUserId: '10',
|
|
65
|
+
platformToken: 'random-string',
|
|
66
|
+
username: 'TestUser',
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`platformToken` is required, but any random non-empty string is accepted.
|
|
71
|
+
|
|
72
|
+
## HTML Integration
|
|
73
|
+
|
|
74
|
+
Use this method for a page that does not use a Vue or React build setup.
|
|
75
|
+
|
|
76
|
+
Place the following code in `index.html`:
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<!doctype html>
|
|
80
|
+
<html lang="en">
|
|
81
|
+
<head>
|
|
82
|
+
<meta charset="UTF-8" />
|
|
83
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
84
|
+
<title>Playsout HTML Demo</title>
|
|
85
|
+
</head>
|
|
86
|
+
<body>
|
|
87
|
+
<div id="game-container"></div>
|
|
88
|
+
|
|
89
|
+
<script src="https://unpkg.com/playsout-web-sdk/index.iife.js"></script>
|
|
90
|
+
<script>
|
|
91
|
+
let loginPromise = null;
|
|
92
|
+
|
|
93
|
+
function login() {
|
|
94
|
+
if (!loginPromise) {
|
|
95
|
+
loginPromise = window.Playsout.Login({
|
|
96
|
+
platform: 'eros',
|
|
97
|
+
platformUserId: '10',
|
|
98
|
+
platformToken: 'random-string',
|
|
99
|
+
username: 'TestUser'
|
|
100
|
+
}).finally(function () {
|
|
101
|
+
loginPromise = null;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return loginPromise;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function ensureLogin() {
|
|
109
|
+
if (!window.Playsout.isLoggedIn) {
|
|
110
|
+
return login();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function bootstrap() {
|
|
115
|
+
await window.Playsout.init({ locale: 'en' });
|
|
116
|
+
|
|
117
|
+
await ensureLogin();
|
|
118
|
+
|
|
120
119
|
window.Playsout.mount('#game-container');
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
window.Playsout.
|
|
139
|
-
window.Playsout.
|
|
140
|
-
window.Playsout.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}, { immediate: true });
|
|
233
|
-
</script>
|
|
234
|
-
|
|
235
|
-
<template>
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
bootstrap().catch(function (error) {
|
|
123
|
+
console.error('Playsout bootstrap failed:', error);
|
|
124
|
+
});
|
|
125
|
+
</script>
|
|
126
|
+
</body>
|
|
127
|
+
</html>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Common HTML / IIFE APIs:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
window.Playsout.init({ locale: 'en' });
|
|
134
|
+
window.Playsout.isLoggedIn;
|
|
135
|
+
window.Playsout.Login(params);
|
|
136
|
+
window.Playsout.getUserInfo();
|
|
137
|
+
window.Playsout.getUser();
|
|
138
|
+
window.Playsout.setLocale('en');
|
|
139
|
+
window.Playsout.getLocale();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Vue 3 Integration
|
|
143
|
+
|
|
144
|
+
### 1. Configure `vite.config.js`
|
|
145
|
+
|
|
146
|
+
Add this configuration to `vite.config.js` or `vite.config.ts` in the Vue project.
|
|
147
|
+
|
|
148
|
+
It tells the Vue compiler that `<playsout-widget>` is a native Web Component rather than a Vue component.
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
import { defineConfig } from 'vite';
|
|
152
|
+
import vue from '@vitejs/plugin-vue';
|
|
153
|
+
|
|
154
|
+
export default defineConfig({
|
|
155
|
+
plugins: [
|
|
156
|
+
vue({
|
|
157
|
+
template: {
|
|
158
|
+
compilerOptions: {
|
|
159
|
+
isCustomElement: (tag) => tag.startsWith('playsout-'),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
}),
|
|
163
|
+
],
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Without this configuration, Vue may report:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
Failed to resolve component: playsout-widget
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 2. Initialize the SDK in `src/main.js`
|
|
174
|
+
|
|
175
|
+
Place this code in the Vue entry file, usually `src/main.js` or `src/main.ts`.
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
import { createApp } from 'vue';
|
|
179
|
+
import { createPlaysoutPlugin } from 'playsout-web-sdk/vue';
|
|
180
|
+
import 'playsout-web-sdk/web-components';
|
|
181
|
+
import App from './App.vue';
|
|
182
|
+
|
|
183
|
+
const app = createApp(App);
|
|
184
|
+
|
|
185
|
+
app.use(createPlaysoutPlugin({
|
|
186
|
+
config: {
|
|
187
|
+
locale: 'en',
|
|
188
|
+
},
|
|
189
|
+
}));
|
|
190
|
+
|
|
191
|
+
app.mount('#app');
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`createPlaysoutPlugin({ config })` automatically calls `init(config)` when the plugin is installed. Vue components normally should not call `init()` again.
|
|
195
|
+
|
|
196
|
+
### 3. Use the SDK in the game page
|
|
197
|
+
|
|
198
|
+
Place this code in the page component that displays the game list. In a new Vue project, it can be placed directly in `src/App.vue`.
|
|
199
|
+
|
|
200
|
+
```vue
|
|
201
|
+
<script setup>
|
|
202
|
+
import { watch } from 'vue';
|
|
203
|
+
import { usePlaysout } from 'playsout-web-sdk/vue';
|
|
204
|
+
|
|
205
|
+
const {
|
|
206
|
+
isInitialized,
|
|
207
|
+
isLoggedIn,
|
|
208
|
+
locale,
|
|
209
|
+
Login,
|
|
210
|
+
} = usePlaysout();
|
|
211
|
+
|
|
212
|
+
let initialLoginChecked = false;
|
|
213
|
+
|
|
214
|
+
watch(isInitialized, (initialized) => {
|
|
215
|
+
if (!initialized || initialLoginChecked) return;
|
|
216
|
+
initialLoginChecked = true;
|
|
217
|
+
if (isLoggedIn.value) return;
|
|
218
|
+
|
|
219
|
+
Login({
|
|
220
|
+
platform: 'eros',
|
|
221
|
+
platformUserId: '10',
|
|
222
|
+
platformToken: 'random-string',
|
|
223
|
+
username: 'TestUser',
|
|
224
|
+
}).catch((error) => {
|
|
225
|
+
console.error('Playsout login flow failed:', error);
|
|
226
|
+
});
|
|
227
|
+
}, { immediate: true });
|
|
228
|
+
</script>
|
|
229
|
+
|
|
230
|
+
<template>
|
|
236
231
|
<playsout-widget
|
|
237
232
|
:locale="locale"
|
|
238
|
-
user-points="1000"
|
|
239
233
|
/>
|
|
240
|
-
</template>
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Vue notes:
|
|
244
|
-
|
|
234
|
+
</template>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Vue notes:
|
|
238
|
+
|
|
245
239
|
- The page waits for plugin initialization, then checks the login state and runs the login flow automatically.
|
|
246
240
|
- `locale` controls the widget language.
|
|
247
241
|
- For a fixed default language, `config: { locale: 'en' }` in the entry file is sufficient. If the application later needs dynamic locale switching, call `setLocale()` and bind `locale`.
|
|
248
|
-
- `user-points="1000"` seeds the widget's frontend gem balance. Iframe game payments can deduct from this in-session balance only.
|
|
249
242
|
- If the application already has a game page, place the logic in that page component.
|
|
250
|
-
|
|
251
|
-
## React Integration
|
|
252
|
-
|
|
253
|
-
### 1. Initialize the SDK in `src/main.jsx`
|
|
254
|
-
|
|
255
|
-
Place this code in the React entry file, usually `src/main.jsx` or `src/main.tsx`.
|
|
256
|
-
|
|
257
|
-
React does not require `isCustomElement` configuration. Tags containing a hyphen, such as `<playsout-widget>`, are handled as Custom Elements.
|
|
258
|
-
|
|
259
|
-
```jsx
|
|
260
|
-
import { createRoot } from 'react-dom/client';
|
|
261
|
-
import { PlaysoutProvider } from 'playsout-web-sdk/react';
|
|
262
|
-
import 'playsout-web-sdk/web-components';
|
|
263
|
-
import App from './App.jsx';
|
|
264
|
-
|
|
265
|
-
createRoot(document.getElementById('root')).render(
|
|
266
|
-
<PlaysoutProvider config={{ locale: 'en' }}>
|
|
267
|
-
<App />
|
|
268
|
-
</PlaysoutProvider>
|
|
269
|
-
);
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
`PlaysoutProvider` automatically calls `init(config)` after receiving `config`. Page components normally should not call `init()` again.
|
|
273
|
-
|
|
274
|
-
### 2. Use the SDK in the game page
|
|
275
|
-
|
|
276
|
-
Place this code in the page component that displays the game list. In a new React project, it can be placed directly in `src/App.jsx`.
|
|
277
|
-
|
|
278
|
-
```jsx
|
|
279
|
-
import { useEffect, useRef } from 'react';
|
|
280
|
-
import { usePlaysout } from 'playsout-web-sdk/react';
|
|
281
|
-
|
|
282
|
-
export default function App() {
|
|
283
|
-
const initialLoginChecked = useRef(false);
|
|
284
|
-
const {
|
|
285
|
-
isInitialized,
|
|
286
|
-
isLoggedIn,
|
|
287
|
-
locale,
|
|
288
|
-
Login,
|
|
289
|
-
} = usePlaysout();
|
|
290
|
-
|
|
291
|
-
useEffect(() => {
|
|
292
|
-
if (!isInitialized || initialLoginChecked.current) return;
|
|
293
|
-
initialLoginChecked.current = true;
|
|
294
|
-
if (isLoggedIn) return;
|
|
295
|
-
|
|
296
|
-
Login({
|
|
297
|
-
platform: 'eros',
|
|
298
|
-
platformUserId: '10',
|
|
299
|
-
platformToken: 'random-string',
|
|
300
|
-
username: 'TestUser',
|
|
301
|
-
})
|
|
302
|
-
.catch((error) => {
|
|
303
|
-
console.error('Playsout login flow failed:', error);
|
|
304
|
-
});
|
|
305
|
-
}, [isInitialized, isLoggedIn, Login]);
|
|
306
|
-
|
|
243
|
+
|
|
244
|
+
## React Integration
|
|
245
|
+
|
|
246
|
+
### 1. Initialize the SDK in `src/main.jsx`
|
|
247
|
+
|
|
248
|
+
Place this code in the React entry file, usually `src/main.jsx` or `src/main.tsx`.
|
|
249
|
+
|
|
250
|
+
React does not require `isCustomElement` configuration. Tags containing a hyphen, such as `<playsout-widget>`, are handled as Custom Elements.
|
|
251
|
+
|
|
252
|
+
```jsx
|
|
253
|
+
import { createRoot } from 'react-dom/client';
|
|
254
|
+
import { PlaysoutProvider } from 'playsout-web-sdk/react';
|
|
255
|
+
import 'playsout-web-sdk/web-components';
|
|
256
|
+
import App from './App.jsx';
|
|
257
|
+
|
|
258
|
+
createRoot(document.getElementById('root')).render(
|
|
259
|
+
<PlaysoutProvider config={{ locale: 'en' }}>
|
|
260
|
+
<App />
|
|
261
|
+
</PlaysoutProvider>
|
|
262
|
+
);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`PlaysoutProvider` automatically calls `init(config)` after receiving `config`. Page components normally should not call `init()` again.
|
|
266
|
+
|
|
267
|
+
### 2. Use the SDK in the game page
|
|
268
|
+
|
|
269
|
+
Place this code in the page component that displays the game list. In a new React project, it can be placed directly in `src/App.jsx`.
|
|
270
|
+
|
|
271
|
+
```jsx
|
|
272
|
+
import { useEffect, useRef } from 'react';
|
|
273
|
+
import { usePlaysout } from 'playsout-web-sdk/react';
|
|
274
|
+
|
|
275
|
+
export default function App() {
|
|
276
|
+
const initialLoginChecked = useRef(false);
|
|
277
|
+
const {
|
|
278
|
+
isInitialized,
|
|
279
|
+
isLoggedIn,
|
|
280
|
+
locale,
|
|
281
|
+
Login,
|
|
282
|
+
} = usePlaysout();
|
|
283
|
+
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
if (!isInitialized || initialLoginChecked.current) return;
|
|
286
|
+
initialLoginChecked.current = true;
|
|
287
|
+
if (isLoggedIn) return;
|
|
288
|
+
|
|
289
|
+
Login({
|
|
290
|
+
platform: 'eros',
|
|
291
|
+
platformUserId: '10',
|
|
292
|
+
platformToken: 'random-string',
|
|
293
|
+
username: 'TestUser',
|
|
294
|
+
})
|
|
295
|
+
.catch((error) => {
|
|
296
|
+
console.error('Playsout login flow failed:', error);
|
|
297
|
+
});
|
|
298
|
+
}, [isInitialized, isLoggedIn, Login]);
|
|
299
|
+
|
|
307
300
|
return (
|
|
308
301
|
<playsout-widget
|
|
309
302
|
locale={locale}
|
|
310
|
-
user-points="1000"
|
|
311
303
|
/>
|
|
312
304
|
);
|
|
313
305
|
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
React notes:
|
|
317
|
-
|
|
318
|
-
- `PlaysoutProvider` initializes the SDK.
|
|
319
|
-
- After Provider initialization, the page checks the login state and runs the login flow once.
|
|
320
|
-
- `usePlaysout()` provides the login state, login method, user information method, and locale APIs.
|
|
321
|
-
- For a fixed default language, `<PlaysoutProvider config={{ locale: 'en' }}>` is sufficient. If the application later needs dynamic locale switching, call `setLocale()` and bind `locale`.
|
|
322
|
-
- React does not need Vue's `isCustomElement` configuration.
|
|
323
|
-
|
|
324
|
-
## Common API Reference
|
|
325
|
-
|
|
326
|
-
| Capability | HTML / IIFE | Vue 3 | React |
|
|
327
|
-
| --- | --- | --- | --- |
|
|
328
|
-
| Initialize | `Playsout.init(config)` | `createPlaysoutPlugin({ config })` | `<PlaysoutProvider config={...}>` |
|
|
329
|
-
| Check login state | `Playsout.isLoggedIn` | `isLoggedIn.value` | `isLoggedIn` |
|
|
330
|
-
| Log in | `Playsout.Login(params)` | `Login(params)` | `Login(params)` |
|
|
331
|
-
| Fetch latest user information | `Playsout.getUserInfo()` | `Playsout.getUserInfo()` | `getUserInfo()` |
|
|
332
|
-
| Read locally stored user information | `Playsout.getUser()` | `Playsout.getUser()` | `user` |
|
|
333
|
-
| Change locale | `Playsout.setLocale('en')` | `setLocale('en')` | `setLocale('en')` |
|
|
334
|
-
| Read current locale | `Playsout.getLocale()` | `locale.value` | `locale` |
|
|
335
|
-
| Log out | `Playsout.logout()` | `logout()` | `logout()` |
|
|
336
|
-
|
|
337
|
-
## Supported Locales
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
'zh' | 'en' | 'ja' | 'ko' | 'vi' | 'th' | 'id' | 'ms'
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
##
|
|
344
|
-
|
|
345
|
-
Pass the value through the `user-points` attribute:
|
|
346
|
-
|
|
347
|
-
```html
|
|
348
|
-
<playsout-widget user-points="1000"></playsout-widget>
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
The SDK currently does not fetch, persist, or recharge the user's gem amount through a backend. `user-points` is supplied by the host application and becomes the widget's in-session frontend balance.
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
React notes:
|
|
309
|
+
|
|
310
|
+
- `PlaysoutProvider` initializes the SDK.
|
|
311
|
+
- After Provider initialization, the page checks the login state and runs the login flow once.
|
|
312
|
+
- `usePlaysout()` provides the login state, login method, user information method, and locale APIs.
|
|
313
|
+
- For a fixed default language, `<PlaysoutProvider config={{ locale: 'en' }}>` is sufficient. If the application later needs dynamic locale switching, call `setLocale()` and bind `locale`.
|
|
314
|
+
- React does not need Vue's `isCustomElement` configuration.
|
|
315
|
+
|
|
316
|
+
## Common API Reference
|
|
317
|
+
|
|
318
|
+
| Capability | HTML / IIFE | Vue 3 | React |
|
|
319
|
+
| --- | --- | --- | --- |
|
|
320
|
+
| Initialize | `Playsout.init(config)` | `createPlaysoutPlugin({ config })` | `<PlaysoutProvider config={...}>` |
|
|
321
|
+
| Check login state | `Playsout.isLoggedIn` | `isLoggedIn.value` | `isLoggedIn` |
|
|
322
|
+
| Log in | `Playsout.Login(params)` | `Login(params)` | `Login(params)` |
|
|
323
|
+
| Fetch latest user information | `Playsout.getUserInfo()` | `Playsout.getUserInfo()` | `getUserInfo()` |
|
|
324
|
+
| Read locally stored user information | `Playsout.getUser()` | `Playsout.getUser()` | `user` |
|
|
325
|
+
| Change locale | `Playsout.setLocale('en')` | `setLocale('en')` | `setLocale('en')` |
|
|
326
|
+
| Read current locale | `Playsout.getLocale()` | `locale.value` | `locale` |
|
|
327
|
+
| Log out | `Playsout.logout()` | `logout()` | `logout()` |
|
|
328
|
+
|
|
329
|
+
## Supported Locales
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
'zh' | 'en' | 'ja' | 'ko' | 'vi' | 'th' | 'id' | 'ms'
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Simulated Payment
|
|
352
336
|
|
|
353
337
|
When a game is opened in iframe detail mode, the widget listens for `privy-bridge` `postMessage` requests from the current iframe only. Supported methods are:
|
|
354
|
-
|
|
355
|
-
- `bridge.handshake`
|
|
356
|
-
- `auth.getUser`
|
|
357
|
-
- `pay.createOrder`
|
|
358
|
-
- `pay.request`
|
|
359
|
-
- `pay.query`
|
|
360
|
-
|
|
361
|
-
`pay.request` opens a localized confirmation dialog. Confirm deducts gems from the in-session balance and emits `gem-balance-change`; cancel and insufficient balance do not deduct gems.
|
|
362
|
-
|
|
363
|
-
## Authentication Expiration
|
|
364
|
-
|
|
365
|
-
The SDK handles authentication recovery internally:
|
|
366
|
-
|
|
367
|
-
1. When a protected API reports that the access token is invalid, the SDK calls the refresh token endpoint.
|
|
368
|
-
2. After a successful refresh, the SDK stores the new token and retries the original request.
|
|
369
|
-
3. If the refresh token is expired or the refresh request fails, the SDK automatically reuses the most recently saved Grab/Eros `Login()` parameters and re-logs in once.
|
|
370
|
-
4. After a successful re-login, the SDK stores both the new token and user information, then retries the original request.
|
|
371
|
-
|
|
372
|
-
The automatic re-login is attempted at most once for an authentication recovery. If it fails, the SDK clears the stored token, user information, and reusable login parameters, changes `isLoggedIn` to `false`, emits `authExpired`, and throws the error to the calling application. TikTok login parameters are not reused automatically.
|
|
373
|
-
|
|
374
|
-
`authExpired` is an optional final-failure notification. Do not start another automatic login loop from this event:
|
|
375
|
-
|
|
376
|
-
```js
|
|
377
|
-
window.Playsout.on('authExpired', function () {
|
|
378
|
-
console.error('Playsout authentication recovery failed');
|
|
379
|
-
});
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
React and Vue adapters synchronize their reactive login state after final recovery failure. The application should catch the failed SDK operation and decide how to present the error to the user.
|
|
383
|
-
|
|
384
|
-
## Image Loading
|
|
385
|
-
|
|
386
|
-
The SDK currently uses online image URLs directly. Persistent SDK image caching is disabled by default, so the SDK does not proactively store images in persistent browser storage.
|
|
338
|
+
|
|
339
|
+
- `bridge.handshake`
|
|
340
|
+
- `auth.getUser`
|
|
341
|
+
- `pay.createOrder`
|
|
342
|
+
- `pay.request`
|
|
343
|
+
- `pay.query`
|
|
344
|
+
|
|
345
|
+
`pay.request` opens a localized confirmation dialog. Confirm deducts gems from the in-session balance and emits `gem-balance-change`; cancel and insufficient balance do not deduct gems.
|
|
346
|
+
|
|
347
|
+
## Authentication Expiration
|
|
348
|
+
|
|
349
|
+
The SDK handles authentication recovery internally:
|
|
350
|
+
|
|
351
|
+
1. When a protected API reports that the access token is invalid, the SDK calls the refresh token endpoint.
|
|
352
|
+
2. After a successful refresh, the SDK stores the new token and retries the original request.
|
|
353
|
+
3. If the refresh token is expired or the refresh request fails, the SDK automatically reuses the most recently saved Grab/Eros `Login()` parameters and re-logs in once.
|
|
354
|
+
4. After a successful re-login, the SDK stores both the new token and user information, then retries the original request.
|
|
355
|
+
|
|
356
|
+
The automatic re-login is attempted at most once for an authentication recovery. If it fails, the SDK clears the stored token, user information, and reusable login parameters, changes `isLoggedIn` to `false`, emits `authExpired`, and throws the error to the calling application. TikTok login parameters are not reused automatically.
|
|
357
|
+
|
|
358
|
+
`authExpired` is an optional final-failure notification. Do not start another automatic login loop from this event:
|
|
359
|
+
|
|
360
|
+
```js
|
|
361
|
+
window.Playsout.on('authExpired', function () {
|
|
362
|
+
console.error('Playsout authentication recovery failed');
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
React and Vue adapters synchronize their reactive login state after final recovery failure. The application should catch the failed SDK operation and decide how to present the error to the user.
|
|
367
|
+
|
|
368
|
+
## Image Loading
|
|
369
|
+
|
|
370
|
+
The SDK currently uses online image URLs directly. Persistent SDK image caching is disabled by default, so the SDK does not proactively store images in persistent browser storage.
|