@cocreate/elements 1.42.9 → 1.43.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/.github/workflows/automated.yml +23 -10
- package/.github/workflows/manual.yml +1 -2
- package/CHANGELOG.md +30 -0
- package/package.json +31 -20
- package/release.config.js +11 -3
- package/src/fetchSrc.js +274 -247
- package/src/index.js +2 -2
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
name: Automated Workflow
|
|
2
|
+
|
|
2
3
|
on:
|
|
3
4
|
push:
|
|
4
5
|
branches:
|
|
5
6
|
- master
|
|
7
|
+
|
|
6
8
|
jobs:
|
|
7
9
|
about:
|
|
8
10
|
runs-on: ubuntu-latest
|
|
@@ -18,26 +20,37 @@ jobs:
|
|
|
18
20
|
with:
|
|
19
21
|
direction: overwrite-github
|
|
20
22
|
githubToken: "${{ secrets.GITHUB }}"
|
|
23
|
+
|
|
21
24
|
release:
|
|
22
25
|
runs-on: ubuntu-latest
|
|
23
26
|
steps:
|
|
24
27
|
- name: Checkout
|
|
25
28
|
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 0 # Required so semantic-release can trace git tags/history
|
|
31
|
+
|
|
26
32
|
- name: Setup Node.js
|
|
27
33
|
uses: actions/setup-node@v4
|
|
28
34
|
with:
|
|
29
|
-
node-version: 22
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@semantic-release/changelog
|
|
35
|
+
node-version: 22
|
|
36
|
+
|
|
37
|
+
- name: Install Semantic Release & Plugins
|
|
38
|
+
# Installs semantic-release and its plugins on the runner
|
|
39
|
+
run: |
|
|
40
|
+
npm install -g semantic-release \
|
|
41
|
+
@semantic-release/changelog \
|
|
42
|
+
@semantic-release/npm \
|
|
43
|
+
@semantic-release/github \
|
|
36
44
|
@semantic-release/git
|
|
37
|
-
|
|
45
|
+
|
|
46
|
+
- name: Run Semantic Release (Native)
|
|
47
|
+
id: semantic
|
|
48
|
+
# This will automatically pick up your export default config file in the repository root
|
|
49
|
+
run: npx semantic-release
|
|
38
50
|
env:
|
|
39
|
-
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
51
|
+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
40
52
|
NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
|
|
53
|
+
|
|
41
54
|
outputs:
|
|
42
55
|
new_release_published: "${{ steps.semantic.outputs.new_release_published }}"
|
|
43
|
-
new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
|
|
56
|
+
new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## [1.43.1](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.43.0...v1.43.1) (2026-07-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* bump dependencies ([1576432](https://github.com/CoCreate-app/CoCreate-elements/commit/15764329c664a34c921bf9ccb9e2d1559d9562b9))
|
|
7
|
+
|
|
8
|
+
# [1.43.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.10...v1.43.0) (2026-07-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* update import statements to include file extensions ([38f073c](https://github.com/CoCreate-app/CoCreate-elements/commit/38f073c45eff68c72eeae63d3c366a8bd7df3e1b))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* update automated workflow and release configuration for improved semantic release handling ([1cbe984](https://github.com/CoCreate-app/CoCreate-elements/commit/1cbe984012f4685ad7a0dbbd7f9ca940e26b9038))
|
|
19
|
+
|
|
20
|
+
## [1.42.10](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.9...v1.42.10) (2026-07-11)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* bump package versions ([92844e1](https://github.com/CoCreate-app/CoCreate-elements/commit/92844e16c8cbfb3928a9ebdd741f147b848e4cb3))
|
|
26
|
+
* improve error handling and code formatting in fetchSrc.js ([4bc0e82](https://github.com/CoCreate-app/CoCreate-elements/commit/4bc0e8217f77d3c7c53f71c18153109abe2ebb87))
|
|
27
|
+
* insert fetch src only from same origin ([5964a33](https://github.com/CoCreate-app/CoCreate-elements/commit/5964a338eac661fb0326c1b2a2241719ad434b57))
|
|
28
|
+
* removed post install and add add packages to apprved list ([f7c6265](https://github.com/CoCreate-app/CoCreate-elements/commit/f7c62658265a8f5b5a13f20b44a90b5400e747f9))
|
|
29
|
+
* semantic version handling ([c34d6ad](https://github.com/CoCreate-app/CoCreate-elements/commit/c34d6ada6acfba573318e9743cdf91196fb1855f))
|
|
30
|
+
|
|
1
31
|
## [1.42.9](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.8...v1.42.9) (2026-03-01)
|
|
2
32
|
|
|
3
33
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/elements",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.1",
|
|
4
4
|
"description": "Fetch content into any html element by using html5 attributes to query data stored in CoCreate headless CMS. If data is changed it will instantly reflect in html tags as changes are broadcasted in realtime",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"elements",
|
|
@@ -16,10 +16,9 @@
|
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"start": "
|
|
20
|
-
"build": "
|
|
21
|
-
"dev": "
|
|
22
|
-
"postinstall": "node -e \"const { execSync } = require('child_process'); try { execSync('coc --version', { stdio: 'ignore' }); } catch (error) { try { execSync('npm install -g @cocreate/cli', { stdio: 'inherit' }); console.log('Installed \"@cocreate/cli\" globally.'); } catch (error) { console.error('Failed to install \"@cocreate/cli\" globally:', error); } }\""
|
|
19
|
+
"start": "webpack --config webpack.config.js",
|
|
20
|
+
"build": "webpack --mode=production --config webpack.config.js",
|
|
21
|
+
"dev": "webpack --config webpack.config.js --watch"
|
|
23
22
|
},
|
|
24
23
|
"repository": {
|
|
25
24
|
"type": "git",
|
|
@@ -36,22 +35,34 @@
|
|
|
36
35
|
"url": "https://github.com/sponsors/CoCreate-app"
|
|
37
36
|
},
|
|
38
37
|
"main": "./src/index.js",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@cocreate/actions": "^1.22.1",
|
|
40
|
+
"@cocreate/crud-client": "^1.35.0",
|
|
41
|
+
"@cocreate/element-prototype": "^1.33.0",
|
|
42
|
+
"@cocreate/filter": "^1.34.0",
|
|
43
|
+
"@cocreate/observer": "^1.20.0",
|
|
44
|
+
"@cocreate/render": "^1.48.0",
|
|
45
|
+
"@cocreate/utils": "^1.44.0"
|
|
46
|
+
},
|
|
39
47
|
"devDependencies": {
|
|
40
|
-
"
|
|
41
|
-
"esbuild": "^0.25.2",
|
|
42
|
-
"esbuild-loader": "^4.3.0",
|
|
43
|
-
"mini-css-extract-plugin": "^1.5.0",
|
|
44
|
-
"webpack": "^5.24.4",
|
|
45
|
-
"webpack-cli": "^4.5.0",
|
|
46
|
-
"webpack-log": "^3.0.1"
|
|
48
|
+
"@cocreate/webpack": "^1.6.0"
|
|
47
49
|
},
|
|
48
|
-
"
|
|
49
|
-
"@cocreate/actions
|
|
50
|
-
"@cocreate/
|
|
51
|
-
"@cocreate/
|
|
52
|
-
"@cocreate/
|
|
53
|
-
"@cocreate/
|
|
54
|
-
"@cocreate/
|
|
55
|
-
"@cocreate/
|
|
50
|
+
"allowScripts": {
|
|
51
|
+
"@cocreate/actions@1.21.4": true,
|
|
52
|
+
"@cocreate/api@1.22.5": true,
|
|
53
|
+
"@cocreate/config@1.13.4": true,
|
|
54
|
+
"@cocreate/crud-client@1.34.6": true,
|
|
55
|
+
"@cocreate/element-prototype@1.31.4": true,
|
|
56
|
+
"@cocreate/elements@1.42.9": true,
|
|
57
|
+
"@cocreate/filter@1.33.6": true,
|
|
58
|
+
"@cocreate/indexeddb@1.23.4": true,
|
|
59
|
+
"@cocreate/local-storage@1.16.5": true,
|
|
60
|
+
"@cocreate/observer@1.19.0": true,
|
|
61
|
+
"@cocreate/organizations@1.30.1": true,
|
|
62
|
+
"@cocreate/render@1.46.1": true,
|
|
63
|
+
"@cocreate/socket-client@1.40.5": true,
|
|
64
|
+
"@cocreate/utils@1.42.2": true,
|
|
65
|
+
"@cocreate/uuid@1.12.4": true,
|
|
66
|
+
"@cocreate/webpack@1.4.3": true
|
|
56
67
|
}
|
|
57
68
|
}
|
package/release.config.js
CHANGED
|
@@ -10,12 +10,20 @@ module.exports = {
|
|
|
10
10
|
changelogFile: "CHANGELOG.md",
|
|
11
11
|
},
|
|
12
12
|
],
|
|
13
|
-
"@semantic-release/npm",
|
|
14
|
-
"@semantic-release/github",
|
|
13
|
+
"@semantic-release/npm",
|
|
15
14
|
[
|
|
16
|
-
"@semantic-release/
|
|
15
|
+
"@semantic-release/github",
|
|
17
16
|
{
|
|
17
|
+
successComment: false,
|
|
18
|
+
failTitle: false,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"@semantic-release/git",
|
|
23
|
+
{
|
|
24
|
+
// Only stage and commit the changelog and package.json
|
|
18
25
|
assets: ["CHANGELOG.md", "package.json"],
|
|
26
|
+
message: "chore(release): ${nextRelease.version} [skip ci]",
|
|
19
27
|
},
|
|
20
28
|
],
|
|
21
29
|
],
|
package/src/fetchSrc.js
CHANGED
|
@@ -2,286 +2,313 @@ import observer from "@cocreate/observer";
|
|
|
2
2
|
import { getRelativePath, ObjectId } from "@cocreate/utils";
|
|
3
3
|
|
|
4
4
|
const selector =
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
"[src]:not(img, video, audio, script, input, iframe, frame, link, source), [source], [stream]";
|
|
6
|
+
|
|
7
|
+
const initializing = new WeakMap();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Validates whether a given URL string points to the current origin.
|
|
11
|
+
* Relative paths (e.g., "/partial.html") resolve to the same origin.
|
|
12
|
+
* @param {string} urlStr - The URL to validate
|
|
13
|
+
* @returns {boolean} True if safe/same-origin, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
function isSameOrigin(urlStr) {
|
|
16
|
+
try {
|
|
17
|
+
// Resolve the URL against the current document's origin.
|
|
18
|
+
const url = new URL(urlStr, window.location.origin);
|
|
19
|
+
return url.origin === window.location.origin;
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error("Invalid URL format:", urlStr, err);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
7
25
|
|
|
8
26
|
function init(elements) {
|
|
9
|
-
|
|
27
|
+
if (elements && !Array.isArray(elements)) elements = [elements];
|
|
10
28
|
|
|
11
|
-
|
|
29
|
+
if (!elements) elements = document.querySelectorAll(selector);
|
|
12
30
|
|
|
13
|
-
|
|
31
|
+
initElements(elements);
|
|
14
32
|
}
|
|
15
33
|
|
|
16
34
|
async function initElements(elements) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
35
|
+
for (let element of elements) {
|
|
36
|
+
let src =
|
|
37
|
+
element.getAttribute("src") ||
|
|
38
|
+
element.getAttribute("source") ||
|
|
39
|
+
element.getAttribute("stream");
|
|
40
|
+
|
|
41
|
+
if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src)) continue;
|
|
42
|
+
|
|
43
|
+
let initialize = initializing.get(element);
|
|
44
|
+
if (initialize && initialize.src === src) continue;
|
|
45
|
+
|
|
46
|
+
initializing.set(element, { src });
|
|
47
|
+
try {
|
|
48
|
+
// --- SECURITY FIX: Conditional Sensitive Headers ---
|
|
49
|
+
// Only attach the local state header if fetching from the same origin.
|
|
50
|
+
let headers = {};
|
|
51
|
+
if (isSameOrigin(src)) {
|
|
52
|
+
let state = localStorage.getItem("state");
|
|
53
|
+
if (state) {
|
|
54
|
+
headers["X-State"] = state;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let response = await fetch(src, { headers });
|
|
59
|
+
|
|
60
|
+
if (response.status === 404 || response.status === 403) {
|
|
61
|
+
element.setAttribute("error", response.status);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (element.tagName === "AUDIO" || element.tagName === "VIDEO") {
|
|
66
|
+
// Media streams can safely load cross-origin without risk of DOM-based XSS
|
|
67
|
+
initMediaSource(element, src);
|
|
68
|
+
} else {
|
|
69
|
+
// --- SECURITY FIX: Cross-Origin HTML Injection Prevention ---
|
|
70
|
+
// Only allow rendering the fetched response directly into the HTML tree if same-origin.
|
|
71
|
+
if (!isSameOrigin(src)) {
|
|
72
|
+
console.warn(`[CoCreateSrc] Blocked inserting fetched text into HTML from cross-origin: ${src}`);
|
|
73
|
+
element.setAttribute("error", "403-forbidden-cross-origin-html");
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (element.hasAttribute("rendered")) {
|
|
78
|
+
element.removeAttribute("rendered");
|
|
79
|
+
}
|
|
80
|
+
let text = await response.text();
|
|
81
|
+
if (text) {
|
|
82
|
+
let path = "";
|
|
83
|
+
let pathElement = element.closest("[path]");
|
|
84
|
+
if (pathElement) {
|
|
85
|
+
path =
|
|
86
|
+
pathElement.getAttribute("path") ||
|
|
87
|
+
getRelativePath();
|
|
88
|
+
} else {
|
|
89
|
+
path = getRelativePath();
|
|
90
|
+
}
|
|
91
|
+
// Replace $relativePath in the fetched text
|
|
92
|
+
if (path) {
|
|
93
|
+
text = text.replaceAll(/\$relativePath\/?/g, path);
|
|
94
|
+
}
|
|
95
|
+
// Replace ObjectId() with a new ObjectId
|
|
96
|
+
text = text.replaceAll("ObjectId()", () => {
|
|
97
|
+
return ObjectId().toString();
|
|
98
|
+
});
|
|
99
|
+
element.setValue(text);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.log("FetchSrc error:" + err);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
73
106
|
}
|
|
74
107
|
|
|
75
108
|
async function initMediaSource(element, src) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
// let blob = await response.json();
|
|
161
|
-
// URL.createObjectURL(blob);
|
|
162
|
-
}
|
|
109
|
+
try {
|
|
110
|
+
let response = await fetch(src);
|
|
111
|
+
let mediaConfig = await response.json();
|
|
112
|
+
let sourceBuffer;
|
|
113
|
+
|
|
114
|
+
const mediaSource = new MediaSource();
|
|
115
|
+
element.src = URL.createObjectURL(mediaSource);
|
|
116
|
+
mediaSource.addEventListener("sourceopen", async () => {
|
|
117
|
+
sourceBuffer = mediaSource.addSourceBuffer(
|
|
118
|
+
`${mediaConfig["content-type"]}; codecs="${mediaConfig.codecs}"`
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
sourceBuffer.addEventListener("updateend", () => {
|
|
122
|
+
console.log(
|
|
123
|
+
"Update ended, buffered ranges:",
|
|
124
|
+
sourceBuffer.buffered
|
|
125
|
+
);
|
|
126
|
+
if (
|
|
127
|
+
!sourceBuffer.updating &&
|
|
128
|
+
mediaSource.readyState === "open"
|
|
129
|
+
) {
|
|
130
|
+
mediaSource.endOfStream();
|
|
131
|
+
|
|
132
|
+
element.addEventListener("ended", () => {
|
|
133
|
+
URL.revokeObjectURL(element.src);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
sourceBuffer.addEventListener("error", (e) => {
|
|
139
|
+
console.error("SourceBuffer error event:", e);
|
|
140
|
+
console.log("MediaSource readyState:", mediaSource.readyState);
|
|
141
|
+
console.log("SourceBuffer updating:", sourceBuffer.updating);
|
|
142
|
+
console.log(
|
|
143
|
+
"SourceBuffer buffered ranges:",
|
|
144
|
+
sourceBuffer.buffered
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
getSegment(sourceBuffer, mediaConfig.segments[0]);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
mediaSource.addEventListener("sourceended", () => {
|
|
152
|
+
console.log("MediaSource ended event fired");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
mediaSource.addEventListener("sourceclose", () => {
|
|
156
|
+
console.log("MediaSource close event fired");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Event listener for seeking
|
|
160
|
+
element.addEventListener("seeking", () => {
|
|
161
|
+
let currentTime = element.currentTime;
|
|
162
|
+
let chunkIndex = Math.floor(currentTime / chunkDuration);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Event listener for seeked
|
|
166
|
+
element.addEventListener("seeked", () => {
|
|
167
|
+
let currentTime = element.currentTime;
|
|
168
|
+
if (isBuffered(element, currentTime)) return;
|
|
169
|
+
|
|
170
|
+
let query = {
|
|
171
|
+
start: { $lte: currentTime },
|
|
172
|
+
end: { $gte: currentTime }
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
let segments = queryData(mediaConfig.segments, query);
|
|
176
|
+
for (let segment of segments) {
|
|
177
|
+
getSegment(sourceBuffer, segment);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
element.addEventListener("timeupdate", function () {
|
|
182
|
+
const bufferEnd = element.buffered.end(0);
|
|
183
|
+
const currentTime = element.currentTime;
|
|
184
|
+
const threshold = 10;
|
|
185
|
+
|
|
186
|
+
if (bufferEnd - currentTime < threshold) {
|
|
187
|
+
getSegment(sourceBuffer, mediaConfig);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
} catch (error) {
|
|
191
|
+
element.src = src;
|
|
192
|
+
}
|
|
163
193
|
}
|
|
164
194
|
|
|
165
195
|
async function getSegment(sourceBuffer, segment) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
let segments = [];
|
|
197
|
+
let data;
|
|
198
|
+
if (segment.array && segment.object) {
|
|
199
|
+
data = { method: "object.read", ...segment };
|
|
200
|
+
data = await crud.send(data);
|
|
201
|
+
if (segment.key) {
|
|
202
|
+
if (Array.isArray(data.object[0][key]))
|
|
203
|
+
segments.push(...data.object[0][key]);
|
|
204
|
+
else segments.push(data.object[0][key]);
|
|
205
|
+
} else segments.push(...data.object);
|
|
206
|
+
segment.src = segments[0];
|
|
207
|
+
segment.src = await segment.src.text();
|
|
208
|
+
} else if (segment.src) {
|
|
209
|
+
// Media segments are safe to fetch cross-origin as they're not processed as HTML
|
|
210
|
+
let response = await fetch(segment.src);
|
|
211
|
+
if (response.status === 404 || response.status === 403) {
|
|
212
|
+
console.warn(`Segment fetch failed with status: ${response.status}`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
segment.src = await response.text();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
appendSegment(sourceBuffer, segment);
|
|
188
219
|
}
|
|
189
220
|
|
|
190
221
|
async function appendSegment(sourceBuffer, segment) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
sourceBuffer.appendBuffer(arrayBuffer);
|
|
215
|
-
console.log(sourceBuffer);
|
|
222
|
+
let arrayBuffer = segment.src;
|
|
223
|
+
if (typeof segment.src === "string") {
|
|
224
|
+
try {
|
|
225
|
+
arrayBuffer = base64ToArrayBuffer(segment.src);
|
|
226
|
+
} catch (e) {
|
|
227
|
+
console.error("Base64 decode error:", e);
|
|
228
|
+
}
|
|
229
|
+
} else if (segment.src instanceof ArrayBuffer) {
|
|
230
|
+
arrayBuffer = segment.src;
|
|
231
|
+
} else if (segment.src instanceof Blob) {
|
|
232
|
+
arrayBuffer = await segment.src.arrayBuffer();
|
|
233
|
+
} else {
|
|
234
|
+
arrayBuffer = base64ToArrayBuffer(segment.src);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (sourceBuffer.updating)
|
|
238
|
+
await new Promise((resolve) =>
|
|
239
|
+
sourceBuffer.addEventListener("updateend", resolve, { once: true })
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
sourceBuffer.appendBuffer(arrayBuffer);
|
|
243
|
+
console.log(sourceBuffer);
|
|
216
244
|
}
|
|
217
245
|
|
|
218
246
|
function isBuffered(element, currentTime) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
247
|
+
for (let i = 0; i < element.buffered.length; i++) {
|
|
248
|
+
if (
|
|
249
|
+
currentTime >= element.buffered.start(i) &&
|
|
250
|
+
currentTime <= element.buffered.end(i)
|
|
251
|
+
) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
228
256
|
}
|
|
229
257
|
|
|
230
258
|
function base64ToBlob(base64, contentType = "") {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
259
|
+
const binaryString = atob(base64.split(",")[1]);
|
|
260
|
+
const len = binaryString.length;
|
|
261
|
+
const uint8Array = new Uint8Array(len);
|
|
262
|
+
for (let i = 0; i < len; i++) {
|
|
263
|
+
uint8Array[i] = binaryString.charCodeAt(i);
|
|
264
|
+
}
|
|
265
|
+
return new Blob([uint8Array], { type: contentType });
|
|
238
266
|
}
|
|
239
267
|
|
|
240
268
|
function base64ToArrayBuffer(base64) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
269
|
+
const binaryString = window.atob(base64.split(",")[1]);
|
|
270
|
+
const len = binaryString.length;
|
|
271
|
+
const bytes = new Uint8Array(len);
|
|
272
|
+
for (let i = 0; i < len; i++) {
|
|
273
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
274
|
+
}
|
|
275
|
+
return bytes.buffer;
|
|
248
276
|
}
|
|
249
277
|
|
|
250
278
|
observer.init({
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
279
|
+
name: "CoCreateSrc",
|
|
280
|
+
types: ["addedNodes"],
|
|
281
|
+
selector: selector,
|
|
282
|
+
callback: function (mutation) {
|
|
283
|
+
init(mutation.target);
|
|
284
|
+
}
|
|
257
285
|
});
|
|
258
286
|
|
|
259
287
|
observer.init({
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
288
|
+
name: "CoCreateSrcOperator",
|
|
289
|
+
types: ["addedNodes"],
|
|
290
|
+
selector: "img",
|
|
291
|
+
callback: function (mutation) {
|
|
292
|
+
let src = mutation.target.getAttribute("src");
|
|
293
|
+
if (src) {
|
|
294
|
+
mutation.target.setAttribute("src", src);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
270
297
|
});
|
|
271
298
|
|
|
272
299
|
observer.init({
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
300
|
+
name: "CoCreateSrcAttributes",
|
|
301
|
+
types: ["attributes"],
|
|
302
|
+
attributeFilter: ["src"],
|
|
303
|
+
selector: selector,
|
|
304
|
+
callback: function (mutation) {
|
|
305
|
+
if (
|
|
306
|
+
mutation.oldValue !==
|
|
307
|
+
mutation.target.getAttribute(mutation.attributeName)
|
|
308
|
+
) {
|
|
309
|
+
init(mutation.target);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
285
312
|
});
|
|
286
313
|
|
|
287
|
-
init();
|
|
314
|
+
init();
|
package/src/index.js
CHANGED
|
@@ -38,8 +38,8 @@ import {
|
|
|
38
38
|
import filter from "@cocreate/filter";
|
|
39
39
|
import { render, renderValue, renderedNodes } from "@cocreate/render";
|
|
40
40
|
import "@cocreate/element-prototype";
|
|
41
|
-
import "./fetchSrc";
|
|
42
|
-
import { reset } from "./form";
|
|
41
|
+
import "./fetchSrc.js";
|
|
42
|
+
import { reset } from "./form.js";
|
|
43
43
|
import "./value.js";
|
|
44
44
|
|
|
45
45
|
const selector = "[storage], [database], [array], [render-json]";
|