@dpgradio/creative 8.1.2 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/lint.yml +4 -4
- package/.github/workflows/publish.yml +6 -7
- package/README.md +1 -1
- package/dev/index.html +19 -0
- package/dev/main.js +20 -0
- package/examples/gtm.html +19 -0
- package/examples/gtm.js +25 -0
- package/package.json +5 -3
- package/src/api/endpoints/Members.js +4 -0
- package/src/socket/SocketConnection.js +45 -0
- package/src/utils/setupAirbrake.js +1 -1
- package/vite.config.js +13 -0
- package/package-lock.json +0 -8362
|
@@ -7,9 +7,9 @@ jobs:
|
|
|
7
7
|
- uses: actions/checkout@v3
|
|
8
8
|
- uses: actions/setup-node@v3
|
|
9
9
|
with:
|
|
10
|
-
node-version:
|
|
11
|
-
cache:
|
|
10
|
+
node-version: 22
|
|
11
|
+
cache: npm
|
|
12
12
|
- name: Install dependencies
|
|
13
|
-
run:
|
|
13
|
+
run: npm ci
|
|
14
14
|
- name: Lint
|
|
15
|
-
run:
|
|
15
|
+
run: npm run lint-check
|
|
@@ -9,13 +9,12 @@ jobs:
|
|
|
9
9
|
- uses: actions/checkout@v3
|
|
10
10
|
- uses: actions/setup-node@v3
|
|
11
11
|
with:
|
|
12
|
-
node-version:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- run:
|
|
18
|
-
- run: yarn publish --new-version ${{ github.event.release.tag_name }}
|
|
12
|
+
node-version: 22
|
|
13
|
+
cache: npm
|
|
14
|
+
registry-url: "https://registry.npmjs.org" # This is needed to make npm publish work...
|
|
15
|
+
- run: npm ci
|
|
16
|
+
- run: npm version ${{ github.event.release.tag_name }} --no-git-tag-version
|
|
17
|
+
- run: npm publish
|
|
19
18
|
env:
|
|
20
19
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
21
20
|
|
package/README.md
CHANGED
package/dev/index.html
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Dev playground</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div class="container">
|
|
10
|
+
<h1>Dev playground</h1>
|
|
11
|
+
|
|
12
|
+
<button onclick="testSocket()">Test Socket Connection</button>
|
|
13
|
+
|
|
14
|
+
<pre id="output"></pre>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<script type="module" src="./main.js"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
package/dev/main.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { socket } from '@dpgradio/creative'
|
|
2
|
+
|
|
3
|
+
const output = document.getElementById('output')
|
|
4
|
+
|
|
5
|
+
function log(...args) {
|
|
6
|
+
const timestamp = new Date().toLocaleTimeString()
|
|
7
|
+
const message = args.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg))).join(' ')
|
|
8
|
+
|
|
9
|
+
output.textContent += `[${timestamp}] ${message}\n`
|
|
10
|
+
output.scrollTop = output.scrollHeight
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
window.testSocket = function () {
|
|
14
|
+
log('Connecting to Qmusic socket...')
|
|
15
|
+
const connection = socket.connect('qmusic_be', 'https://socket.qmusic.be/api', {
|
|
16
|
+
debug: true,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
connection.subscribe('plays').on('play', log, { backlog: 1 })
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>GTM and Privacy Test with Nonce</title>
|
|
7
|
+
|
|
8
|
+
<meta http-equiv="Content-Security-Policy" content="
|
|
9
|
+
default-src 'self' 'nonce-abcd1234' *.radio.dpgmedia.net;
|
|
10
|
+
script-src 'self' 'nonce-abcd1234' *.radio.dpgmedia.net;
|
|
11
|
+
style-src 'self' 'unsafe-inline';
|
|
12
|
+
">
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>GTM and Privacy Test with Nonce</h1>
|
|
16
|
+
|
|
17
|
+
<script nonce="abcd1234" type="module" src="gtm.js"></script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
package/examples/gtm.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { configuration, dataLayer, privacy } from '../src/index.js'
|
|
2
|
+
|
|
3
|
+
async function testGTMAndPrivacy() {
|
|
4
|
+
const stationId = 'qmusic_be'
|
|
5
|
+
await configuration.retrieveConfigForStation(stationId)
|
|
6
|
+
console.log('Configuration retrieved:', configuration.config())
|
|
7
|
+
|
|
8
|
+
// Generate a random nonce (in a real scenario, this should be generated server-side)
|
|
9
|
+
// const nonce = Math.random().toString(36).substring(2, 15);
|
|
10
|
+
const nonce = 'abcd1234'
|
|
11
|
+
// Initialize dataLayer with the nonce
|
|
12
|
+
dataLayer.initialize({ nonce: nonce })
|
|
13
|
+
|
|
14
|
+
// Push a custom event to test
|
|
15
|
+
dataLayer.pushEvent('test_event', { message: 'Hello, GTM!' })
|
|
16
|
+
|
|
17
|
+
console.log('GTM initialized with nonce:', nonce)
|
|
18
|
+
|
|
19
|
+
// Initialize privacy settings with default values and nonce
|
|
20
|
+
privacy.initialize(undefined, undefined, undefined, { nonce: nonce })
|
|
21
|
+
|
|
22
|
+
console.log('Privacy settings initialized')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
testGTMAndPrivacy()
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dpgradio/creative",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0",
|
|
4
4
|
"description": "Support package for standalone Javascript applications",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest",
|
|
8
8
|
"lint-check": "eslint --ext .js --ignore-path .gitignore src",
|
|
9
|
-
"lint": "
|
|
9
|
+
"lint": "npm run lint-check --fix",
|
|
10
|
+
"dev": "vite dev --open"
|
|
10
11
|
},
|
|
11
12
|
"repository": {
|
|
12
13
|
"type": "git",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"eslint": "^8.32.0",
|
|
34
35
|
"eslint-plugin-import": "^2.27.5",
|
|
35
36
|
"jest": "^29.4.0",
|
|
36
|
-
"jest-environment-jsdom": "^29.4.0"
|
|
37
|
+
"jest-environment-jsdom": "^29.4.0",
|
|
38
|
+
"vite": "^6.3.5"
|
|
37
39
|
}
|
|
38
40
|
}
|
|
@@ -5,6 +5,10 @@ export default class Members extends Endpoint {
|
|
|
5
5
|
return await this.api.request().get('/members/me')
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
async basicInfo(profileId, email) {
|
|
9
|
+
return await this.api.request().get(`/members/basic-info/${profileId}`, { email: email })
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
async updateProfile(profile) {
|
|
9
13
|
return await this.api.request().put('/members/me', { profile })
|
|
10
14
|
}
|
|
@@ -11,6 +11,7 @@ export default class SocketConnection {
|
|
|
11
11
|
this.messages = []
|
|
12
12
|
this.lastAttempt = 1
|
|
13
13
|
this.reconnecting = false
|
|
14
|
+
this.heartbeatTimeout = null
|
|
14
15
|
|
|
15
16
|
this.connect()
|
|
16
17
|
}
|
|
@@ -31,11 +32,18 @@ export default class SocketConnection {
|
|
|
31
32
|
|
|
32
33
|
this.reconnecting = false
|
|
33
34
|
this.flushMessages()
|
|
35
|
+
this._startHeartbeatTimeout()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.socket.onheartbeat = () => {
|
|
39
|
+
this._resetHeartbeatTimeout()
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
this.socket.onmessage = (event) => {
|
|
37
43
|
this.log('>>>', event.data)
|
|
38
44
|
|
|
45
|
+
this._resetHeartbeatTimeout()
|
|
46
|
+
|
|
39
47
|
try {
|
|
40
48
|
const message = JSON.parse(event.data)
|
|
41
49
|
this.processMessage(message)
|
|
@@ -48,6 +56,8 @@ export default class SocketConnection {
|
|
|
48
56
|
this.socket.onclose = (event) => {
|
|
49
57
|
this.log(`Disconnected ${event.code}`, event)
|
|
50
58
|
|
|
59
|
+
this._clearHeartbeatTimeout()
|
|
60
|
+
|
|
51
61
|
// This is a technical issue, try again
|
|
52
62
|
if ([1000, 1001, 1002, 1003, 1004, 1005, 1006, 2000].includes(event.code)) {
|
|
53
63
|
this.reconnecting = true
|
|
@@ -166,4 +176,39 @@ export default class SocketConnection {
|
|
|
166
176
|
this._sendAuthentication(auth)
|
|
167
177
|
}
|
|
168
178
|
}
|
|
179
|
+
|
|
180
|
+
_isWebsocketTransport() {
|
|
181
|
+
return (
|
|
182
|
+
this.socket.protocol === 'websocket' ||
|
|
183
|
+
(this.socket._transport && this.socket._transport.transportName === 'websocket')
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_startHeartbeatTimeout() {
|
|
188
|
+
if (this.options.heartbeatTimeout === false || !this._isWebsocketTransport()) {
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this._clearHeartbeatTimeout()
|
|
193
|
+
|
|
194
|
+
this.heartbeatTimeout = setTimeout(() => {
|
|
195
|
+
this.log('Heartbeat timeout - closing connection')
|
|
196
|
+
this.socket._close(1006, 'Heartbeat timeout')
|
|
197
|
+
}, this.options.heartbeatTimeout || 35000)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
_resetHeartbeatTimeout() {
|
|
201
|
+
if (!this._isWebsocketTransport()) {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this._startHeartbeatTimeout()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_clearHeartbeatTimeout() {
|
|
209
|
+
if (this.heartbeatTimeout) {
|
|
210
|
+
clearTimeout(this.heartbeatTimeout)
|
|
211
|
+
this.heartbeatTimeout = null
|
|
212
|
+
}
|
|
213
|
+
}
|
|
169
214
|
}
|