@cocreate/elements 1.42.9 → 1.43.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.
@@ -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 # Required for the latest semantic-release plugins
30
- - name: Semantic Release
31
- uses: cycjimmy/semantic-release-action@v4 # Update to v4 for better Node 20+ support
32
- id: semantic
33
- with:
34
- extra_plugins: |
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
- @semantic-release/github
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 }}" # Use the built-in token if possible
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 }}"
@@ -14,8 +14,7 @@ jobs:
14
14
  env:
15
15
  DRY_RUN: ${{ github.event.inputs.dry_run }}
16
16
  GITHUB_TOKEN: "${{ secrets.GITHUB }}"
17
- NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
18
-
17
+
19
18
  steps:
20
19
  - name: Checkout
21
20
  uses: actions/checkout@v3
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ # [1.43.0](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.10...v1.43.0) (2026-07-17)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * update import statements to include file extensions ([38f073c](https://github.com/CoCreate-app/CoCreate-elements/commit/38f073c45eff68c72eeae63d3c366a8bd7df3e1b))
7
+
8
+
9
+ ### Features
10
+
11
+ * update automated workflow and release configuration for improved semantic release handling ([1cbe984](https://github.com/CoCreate-app/CoCreate-elements/commit/1cbe984012f4685ad7a0dbbd7f9ca940e26b9038))
12
+
13
+ ## [1.42.10](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.9...v1.42.10) (2026-07-11)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * bump package versions ([92844e1](https://github.com/CoCreate-app/CoCreate-elements/commit/92844e16c8cbfb3928a9ebdd741f147b848e4cb3))
19
+ * improve error handling and code formatting in fetchSrc.js ([4bc0e82](https://github.com/CoCreate-app/CoCreate-elements/commit/4bc0e8217f77d3c7c53f71c18153109abe2ebb87))
20
+ * insert fetch src only from same origin ([5964a33](https://github.com/CoCreate-app/CoCreate-elements/commit/5964a338eac661fb0326c1b2a2241719ad434b57))
21
+ * removed post install and add add packages to apprved list ([f7c6265](https://github.com/CoCreate-app/CoCreate-elements/commit/f7c62658265a8f5b5a13f20b44a90b5400e747f9))
22
+ * semantic version handling ([c34d6ad](https://github.com/CoCreate-app/CoCreate-elements/commit/c34d6ada6acfba573318e9743cdf91196fb1855f))
23
+
1
24
  ## [1.42.9](https://github.com/CoCreate-app/CoCreate-elements/compare/v1.42.8...v1.42.9) (2026-03-01)
2
25
 
3
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/elements",
3
- "version": "1.42.9",
3
+ "version": "1.43.0",
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",
@@ -18,8 +18,7 @@
18
18
  "scripts": {
19
19
  "start": "npx webpack --config webpack.config.js",
20
20
  "build": "npx webpack --mode=production --config webpack.config.js",
21
- "dev": "npx webpack --config webpack.config.js --watch",
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); } }\""
21
+ "dev": "npx 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.21.4",
40
+ "@cocreate/crud-client": "^1.34.6",
41
+ "@cocreate/element-prototype": "^1.31.4",
42
+ "@cocreate/filter": "^1.33.6",
43
+ "@cocreate/observer": "^1.19.0",
44
+ "@cocreate/render": "^1.46.1",
45
+ "@cocreate/utils": "^1.42.2"
46
+ },
39
47
  "devDependencies": {
40
- "css-loader": "^5.1.3",
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.4.3"
47
49
  },
48
- "dependencies": {
49
- "@cocreate/actions": "^1.21.1",
50
- "@cocreate/crud-client": "^1.34.2",
51
- "@cocreate/element-prototype": "^1.29.1",
52
- "@cocreate/filter": "^1.33.2",
53
- "@cocreate/observer": "^1.18.1",
54
- "@cocreate/render": "^1.45.2",
55
- "@cocreate/utils": "^1.39.0"
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/git",
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
- "[src]:not(img, video, audio, script, input, iframe, frame, link, source), [source], [stream]";
6
- const textExtensions = ['html','htm','xhtml','css','js','mjs','cjs','json','jsonc','json5','xml','xsd','xsl','xslt','svg','md','markdown','scss','sass','less','vue','jsx','tsx','graphql','gql','htc','webmanifest','txt','csv','tsv','yaml','yml','toml','ini','log','dat','env','c','cc','cpp','cxx','h','hh','hpp','hxx','m','mm','cs','java','jsp','properties','py','pyc','pyd','pyo','rb','erb','php','phtml','php3','php4','php5','php7','phps','go','rs','swift','kt','kts','ts','pl','pm','pod','sh','bash','zsh','ksh','csh','tcsh','ps1','psm1','psd1','bat','cmd','sql','r','Rprofile','Rmd','lua','hs','lhs','erl','hrl','scala','sbt','d','f','for','f77','f90','f95','f03','f08','adb','ads','cbl','cob','cpy','lisp','lsp','scm','ss','pro','plg','vb','vbs','dart','asm','s','conf','cfg','config','ini','env','npmrc','yarnrc','gitattributes','gitignore','gitmodules','gitkeep','editorconfig','prettierrc','eslintrc','eslintignore','browserslistrc','package.json','package-lock.json','tsconfig.json','babelrc','vite.config.js','rollup.config.js','webpack.config.js','procfile','dockerfile','dockerignore','makefile','gradle','groovy','pom','properties','service','target','rst','adoc','asciidoc','tex','latex','textile','org','wiki','nfo','rtf','gcode','patch','diff','log','reg','map','sub','srt','dic','wml','rss','atom','gpx','kml','kmz','vcf','vcard','ics','ical','ps','eps','mf','lic','license','pem','key','crt','cert','pub','tpl','liquid','mustache','hbs','twig','blade.php','ejs','coffee','litcoffee','jl','nim','zig','wgsl']; const initializing = new Map();
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
- if (elements && !Array.isArray(elements)) elements = [elements];
27
+ if (elements && !Array.isArray(elements)) elements = [elements];
10
28
 
11
- if (!elements) elements = document.querySelectorAll(selector);
29
+ if (!elements) elements = document.querySelectorAll(selector);
12
30
 
13
- initElements(elements);
31
+ initElements(elements);
14
32
  }
15
33
 
16
34
  async function initElements(elements) {
17
- for (let element of elements) {
18
- let src =
19
- element.getAttribute("src") ||
20
- element.getAttribute("source") ||
21
- element.getAttribute("stream");
22
-
23
- if (!src || /{{\s*([\w\W]+)\s*}}/g.test(src)) continue;
24
-
25
- let initialize = initializing.get(element);
26
- if (initialize && initialize.src === src) continue;
27
-
28
- initializing.set(element, { src });
29
- try {
30
- let state = localStorage.getItem("state"); // Assume this is your state object
31
- let response = await fetch(src, {
32
- headers: {
33
- "X-State": state // Custom header to send state
34
- }
35
- });
36
-
37
- if (element.tagName === "AUDIO" || element.tagName === "VIDEO") {
38
- initMediaSource(element, src);
39
- } else {
40
- if (src && !textExtensions.includes(src.split('.').pop())) continue
41
-
42
- if (element.hasAttribute("rendered")) {
43
- element.removeAttribute("rendered");
44
- // continue;
45
- }
46
- let text = await response.text();
47
- if (text) {
48
- let path = "";
49
- let pathElement = element.closest("[path]");
50
- if (pathElement) {
51
- path =
52
- pathElement.getAttribute("path") ||
53
- getRelativePath();
54
- } else {
55
- path = getRelativePath();
56
- }
57
- // Replace $relativePath in the fetched text
58
- if (path) {
59
- text = text.replaceAll(/\$relativePath\/?/g, path);
60
- }
61
- // Replace ObjectId() with a new ObjectId
62
- text = text.replaceAll("ObjectId()", () => {
63
- // Generate a NEW ObjectId inside the function
64
- return ObjectId().toString(); // Return its string representation
65
- });
66
- element.setValue(text);
67
- }
68
- }
69
- } catch (err) {
70
- console.log("FetchSrc error:" + err);
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
- try {
77
- let mediaConfig = await response.json();
78
- let sourceBuffer;
79
-
80
- const mediaSource = new MediaSource();
81
- element.src = URL.createObjectURL(mediaSource);
82
- mediaSource.addEventListener("sourceopen", async () => {
83
- sourceBuffer = mediaSource.addSourceBuffer(
84
- `${mediaConfig["content-type"]}; codecs="${mediaConfig.codecs}"`
85
- );
86
-
87
- sourceBuffer.addEventListener("updateend", () => {
88
- console.log(
89
- "Update ended, buffered ranges:",
90
- sourceBuffer.buffered
91
- );
92
- if (
93
- !sourceBuffer.updating &&
94
- mediaSource.readyState === "open"
95
- ) {
96
- mediaSource.endOfStream();
97
-
98
- element.addEventListener("ended", () => {
99
- URL.revokeObjectURL(element.src);
100
- });
101
- }
102
- });
103
-
104
- sourceBuffer.addEventListener("error", (e) => {
105
- console.error("SourceBuffer error event:", e);
106
- console.log("MediaSource readyState:", mediaSource.readyState);
107
- console.log("SourceBuffer updating:", sourceBuffer.updating);
108
- console.log(
109
- "SourceBuffer buffered ranges:",
110
- sourceBuffer.buffered
111
- );
112
- // Any other state information you can log
113
- });
114
-
115
- getSegment(sourceBuffer, mediaConfig.segments[0]);
116
- });
117
-
118
- mediaSource.addEventListener("sourceended", () => {
119
- console.log("MediaSource ended event fired");
120
- });
121
-
122
- mediaSource.addEventListener("sourceclose", () => {
123
- console.log("MediaSource close event fired");
124
- });
125
-
126
- // Event listener for seeking
127
- element.addEventListener("seeking", () => {
128
- let currentTime = element.currentTime;
129
- let chunkIndex = Math.floor(currentTime / chunkDuration);
130
- });
131
-
132
- // Event listener for seeked
133
- element.addEventListener("seeked", () => {
134
- let currentTime = element.currentTime;
135
- if (isBuffered(element, currentTime)) return;
136
-
137
- let query = {
138
- start: { $lte: currentTime },
139
- end: { $gte: currentTime }
140
- };
141
-
142
- let segments = queryData(mediaConfig.segments, query);
143
- for (let segment of segments) {
144
- getSegment(sourceBuffer, segment);
145
- }
146
- });
147
-
148
- element.addEventListener("timeupdate", function () {
149
- const bufferEnd = element.buffered.end(0);
150
- const currentTime = element.currentTime;
151
- const threshold = 10; // seconds before buffer end to fetch the next segment
152
-
153
- if (bufferEnd - currentTime < threshold) {
154
- // Time to fetch the next segment
155
- getSegment(sourceBuffer, mediaConfig);
156
- }
157
- });
158
- } catch (error) {
159
- element.src = src;
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
- // TODO: use socket/crud/file with room using the url to get one or more segments and append
167
- let segments = [];
168
- let data;
169
- if (segment.array && segment.object) {
170
- data = { method: "object.read", ...segment };
171
- data = await crud.send(data);
172
- if (segment.key) {
173
- // TODO: utils.getValuefromObject
174
- if (Array.isArray(data.object[0][key]))
175
- segments.push(...data.object[0][key]);
176
- else segments.push(data.object[0][key]);
177
- } else segments.push(...data.object);
178
- segment.src = segments[0];
179
- segment.src = await segment.src.text();
180
- // TODO: handle segment array as
181
- } else if (segment.src) {
182
- // TODO: handle 404, or whether src was fetched or not
183
- segment.src = await fetch(segment.src);
184
- segment.src = await segment.src.text();
185
- }
186
-
187
- appendSegment(sourceBuffer, segment);
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
- let arrayBuffer = segment.src;
192
- if (typeof segment.src === "string") {
193
- try {
194
- arrayBuffer = base64ToArrayBuffer(segment.src);
195
- } catch (e) {
196
- console.error("Base64 decode error:", e);
197
- }
198
- } else if (segment.src instanceof ArrayBuffer) {
199
- arrayBuffer = segment.src;
200
- } else if (segment.src instanceof Blob) {
201
- arrayBuffer = await segment.src.arrayBuffer();
202
- } else {
203
- arrayBuffer = base64ToArrayBuffer(segment.src);
204
-
205
- // arrayBuffer = await segment.src.arrayBuffer();
206
- }
207
-
208
- // Wait for the source buffer to be ready for updates
209
- if (sourceBuffer.updating)
210
- await new Promise((resolve) =>
211
- sourceBuffer.addEventListener("updateend", resolve, { once: true })
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
- for (let i = 0; i < element.buffered.length; i++) {
220
- if (
221
- currentTime >= element.buffered.start(i) &&
222
- currentTime <= element.buffered.end(i)
223
- ) {
224
- return true; // The currentTime is within a buffered range
225
- }
226
- }
227
- return false; // The currentTime is not buffered
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
- const binaryString = atob(base64.split(",")[1]);
232
- const len = binaryString.length;
233
- const uint8Array = new Uint8Array(len);
234
- for (let i = 0; i < len; i++) {
235
- uint8Array[i] = binaryString.charCodeAt(i);
236
- }
237
- return new Blob([uint8Array], { type: contentType });
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
- const binaryString = window.atob(base64.split(",")[1]); // Decode base64
242
- const len = binaryString.length;
243
- const bytes = new Uint8Array(len);
244
- for (let i = 0; i < len; i++) {
245
- bytes[i] = binaryString.charCodeAt(i);
246
- }
247
- return bytes.buffer; // Return ArrayBuffer
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
- name: "CoCreateSrc",
252
- types: ["addedNodes"],
253
- selector: selector,
254
- callback: function (mutation) {
255
- init(mutation.target);
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
- name: "CoCreateSrcOperator",
261
- types: ["addedNodes"],
262
- selector: "img",
263
- // selector: "img, video, audio, script, input, iframe, frame, link, source",
264
- callback: function (mutation) {
265
- let src = mutation.target.getAttribute("src");
266
- if (src) {
267
- mutation.target.setAttribute("src", src);
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
- name: "CoCreateSrcAttributes",
274
- types: ["attributes"],
275
- attributeFilter: ["src"],
276
- selector: selector,
277
- callback: function (mutation) {
278
- if (
279
- mutation.oldValue !==
280
- mutation.target.getAttribute(mutation.attributeName)
281
- ) {
282
- init(mutation.target);
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]";