k-l-lambda Claude commited on
Commit
f553531
·
1 Parent(s): cc0f5f7

feat: add coi-serviceworker for SharedArrayBuffer support

Browse files

Enables cross-origin isolation on client side for ONNX Runtime Web
multi-threading support without requiring server-side COOP/COEP headers.

This fixes VS AI mode which requires SharedArrayBuffer for ONNX inference.

Co-Authored-By: Claude <noreply@anthropic.com>

trigo-web/app/dist/coi-serviceworker.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
2
+ let coepCredentialless = false;
3
+ if (typeof window === 'undefined') {
4
+ self.addEventListener("install", () => self.skipWaiting());
5
+ self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
6
+
7
+ self.addEventListener("message", (ev) => {
8
+ if (!ev.data) {
9
+ return;
10
+ } else if (ev.data.type === "deregister") {
11
+ self.registration
12
+ .unregister()
13
+ .then(() => {
14
+ return self.clients.matchAll();
15
+ })
16
+ .then(clients => {
17
+ clients.forEach((client) => client.navigate(client.url));
18
+ });
19
+ } else if (ev.data.type === "coepCredentialless") {
20
+ coepCredentialless = ev.data.value;
21
+ }
22
+ });
23
+
24
+ self.addEventListener("fetch", function (event) {
25
+ const r = event.request;
26
+ if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
27
+ return;
28
+ }
29
+
30
+ const request = (coepCredentialless && r.mode === "no-cors")
31
+ ? new Request(r, {
32
+ credentials: "omit",
33
+ })
34
+ : r;
35
+ event.respondWith(
36
+ fetch(request)
37
+ .then((response) => {
38
+ if (response.status === 0) {
39
+ return response;
40
+ }
41
+
42
+ const newHeaders = new Headers(response.headers);
43
+ newHeaders.set("Cross-Origin-Embedder-Policy",
44
+ coepCredentialless ? "credentialless" : "require-corp"
45
+ );
46
+ if (!coepCredentialless) {
47
+ newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
48
+ }
49
+ newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
50
+
51
+ return new Response(response.body, {
52
+ status: response.status,
53
+ statusText: response.statusText,
54
+ headers: newHeaders,
55
+ });
56
+ })
57
+ .catch((e) => console.error(e))
58
+ );
59
+ });
60
+
61
+ } else {
62
+ (() => {
63
+ // You can customize the behavior of this script through a global `coi` variable.
64
+ const coi = {
65
+ shouldRegister: () => true,
66
+ shouldDeregister: () => false,
67
+ coepCredentialless: () => !(window.chrome || window.netscape),
68
+ doReload: () => window.location.reload(),
69
+ quiet: false,
70
+ ...window.coi
71
+ };
72
+
73
+ const n = navigator;
74
+
75
+ if (n.serviceWorker && n.serviceWorker.controller) {
76
+ n.serviceWorker.controller.postMessage({
77
+ type: "coepCredentialless",
78
+ value: coi.coepCredentialless(),
79
+ });
80
+
81
+ if (coi.shouldDeregister()) {
82
+ n.serviceWorker.controller.postMessage({ type: "deregister" });
83
+ }
84
+ }
85
+
86
+ // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
87
+ // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
88
+ if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
89
+
90
+ if (!window.isSecureContext) {
91
+ !coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
92
+ return;
93
+ }
94
+
95
+ // In some environments (e.g. Chrome incognito mode) this won't be available
96
+ if (n.serviceWorker) {
97
+ n.serviceWorker.register(window.document.currentScript.src).then(
98
+ (registration) => {
99
+ !coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
100
+
101
+ registration.addEventListener("updatefound", () => {
102
+ !coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
103
+ coi.doReload();
104
+ });
105
+
106
+ // If the registration is active, but it's not controlling the page
107
+ if (registration.active && !n.serviceWorker.controller) {
108
+ !coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
109
+ coi.doReload();
110
+ }
111
+ },
112
+ (err) => {
113
+ !coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
114
+ }
115
+ );
116
+ }
117
+ })();
118
+ }
trigo-web/app/dist/index.html CHANGED
@@ -5,6 +5,8 @@
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Trigo - 3D Go Game</title>
 
 
8
  <script type="module" crossorigin src="/assets/index-cSsYvfzN.js"></script>
9
  <link rel="stylesheet" crossorigin href="/assets/index-DHcFs21z.css">
10
  </head>
 
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Trigo - 3D Go Game</title>
8
+ <!-- Enable cross-origin isolation for SharedArrayBuffer (needed for ONNX multi-threading) -->
9
+ <script src="/coi-serviceworker.js"></script>
10
  <script type="module" crossorigin src="/assets/index-cSsYvfzN.js"></script>
11
  <link rel="stylesheet" crossorigin href="/assets/index-DHcFs21z.css">
12
  </head>
trigo-web/app/index.html CHANGED
@@ -5,6 +5,8 @@
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Trigo - 3D Go Game</title>
 
 
8
  </head>
9
  <body>
10
  <div id="app"></div>
 
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
  <title>Trigo - 3D Go Game</title>
8
+ <!-- Enable cross-origin isolation for SharedArrayBuffer (needed for ONNX multi-threading) -->
9
+ <script src="/coi-serviceworker.js"></script>
10
  </head>
11
  <body>
12
  <div id="app"></div>
trigo-web/package-lock.json CHANGED
@@ -9,6 +9,7 @@
9
  "version": "1.0.0",
10
  "license": "MIT",
11
  "dependencies": {
 
12
  "dotenv": "^17.2.3"
13
  },
14
  "devDependencies": {
@@ -1214,6 +1215,11 @@
1214
  "node": ">=20"
1215
  }
1216
  },
 
 
 
 
 
1217
  "node_modules/color-convert": {
1218
  "version": "2.0.1",
1219
  "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
 
9
  "version": "1.0.0",
10
  "license": "MIT",
11
  "dependencies": {
12
+ "coi-serviceworker": "^0.1.7",
13
  "dotenv": "^17.2.3"
14
  },
15
  "devDependencies": {
 
1215
  "node": ">=20"
1216
  }
1217
  },
1218
+ "node_modules/coi-serviceworker": {
1219
+ "version": "0.1.7",
1220
+ "resolved": "https://registry.npmjs.org/coi-serviceworker/-/coi-serviceworker-0.1.7.tgz",
1221
+ "integrity": "sha512-bjSUqEngCPOkErY2vbyWsaIGCNRODYzlNycaREVw5s12/C8SM+RnRUUeX6pZbTtov6C52ZLY/+tvHK+BDxuUuA=="
1222
+ },
1223
  "node_modules/color-convert": {
1224
  "version": "2.0.1",
1225
  "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
trigo-web/package.json CHANGED
@@ -59,6 +59,7 @@
59
  "yargs": "^18.0.0"
60
  },
61
  "dependencies": {
 
62
  "dotenv": "^17.2.3"
63
  }
64
  }
 
59
  "yargs": "^18.0.0"
60
  },
61
  "dependencies": {
62
+ "coi-serviceworker": "^0.1.7",
63
  "dotenv": "^17.2.3"
64
  }
65
  }
trigo-web/public/coi-serviceworker.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
2
+ let coepCredentialless = false;
3
+ if (typeof window === 'undefined') {
4
+ self.addEventListener("install", () => self.skipWaiting());
5
+ self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
6
+
7
+ self.addEventListener("message", (ev) => {
8
+ if (!ev.data) {
9
+ return;
10
+ } else if (ev.data.type === "deregister") {
11
+ self.registration
12
+ .unregister()
13
+ .then(() => {
14
+ return self.clients.matchAll();
15
+ })
16
+ .then(clients => {
17
+ clients.forEach((client) => client.navigate(client.url));
18
+ });
19
+ } else if (ev.data.type === "coepCredentialless") {
20
+ coepCredentialless = ev.data.value;
21
+ }
22
+ });
23
+
24
+ self.addEventListener("fetch", function (event) {
25
+ const r = event.request;
26
+ if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
27
+ return;
28
+ }
29
+
30
+ const request = (coepCredentialless && r.mode === "no-cors")
31
+ ? new Request(r, {
32
+ credentials: "omit",
33
+ })
34
+ : r;
35
+ event.respondWith(
36
+ fetch(request)
37
+ .then((response) => {
38
+ if (response.status === 0) {
39
+ return response;
40
+ }
41
+
42
+ const newHeaders = new Headers(response.headers);
43
+ newHeaders.set("Cross-Origin-Embedder-Policy",
44
+ coepCredentialless ? "credentialless" : "require-corp"
45
+ );
46
+ if (!coepCredentialless) {
47
+ newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
48
+ }
49
+ newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
50
+
51
+ return new Response(response.body, {
52
+ status: response.status,
53
+ statusText: response.statusText,
54
+ headers: newHeaders,
55
+ });
56
+ })
57
+ .catch((e) => console.error(e))
58
+ );
59
+ });
60
+
61
+ } else {
62
+ (() => {
63
+ // You can customize the behavior of this script through a global `coi` variable.
64
+ const coi = {
65
+ shouldRegister: () => true,
66
+ shouldDeregister: () => false,
67
+ coepCredentialless: () => !(window.chrome || window.netscape),
68
+ doReload: () => window.location.reload(),
69
+ quiet: false,
70
+ ...window.coi
71
+ };
72
+
73
+ const n = navigator;
74
+
75
+ if (n.serviceWorker && n.serviceWorker.controller) {
76
+ n.serviceWorker.controller.postMessage({
77
+ type: "coepCredentialless",
78
+ value: coi.coepCredentialless(),
79
+ });
80
+
81
+ if (coi.shouldDeregister()) {
82
+ n.serviceWorker.controller.postMessage({ type: "deregister" });
83
+ }
84
+ }
85
+
86
+ // If we're already coi: do nothing. Perhaps it's due to this script doing its job, or COOP/COEP are
87
+ // already set from the origin server. Also if the browser has no notion of crossOriginIsolated, just give up here.
88
+ if (window.crossOriginIsolated !== false || !coi.shouldRegister()) return;
89
+
90
+ if (!window.isSecureContext) {
91
+ !coi.quiet && console.log("COOP/COEP Service Worker not registered, a secure context is required.");
92
+ return;
93
+ }
94
+
95
+ // In some environments (e.g. Chrome incognito mode) this won't be available
96
+ if (n.serviceWorker) {
97
+ n.serviceWorker.register(window.document.currentScript.src).then(
98
+ (registration) => {
99
+ !coi.quiet && console.log("COOP/COEP Service Worker registered", registration.scope);
100
+
101
+ registration.addEventListener("updatefound", () => {
102
+ !coi.quiet && console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
103
+ coi.doReload();
104
+ });
105
+
106
+ // If the registration is active, but it's not controlling the page
107
+ if (registration.active && !n.serviceWorker.controller) {
108
+ !coi.quiet && console.log("Reloading page to make use of COOP/COEP Service Worker.");
109
+ coi.doReload();
110
+ }
111
+ },
112
+ (err) => {
113
+ !coi.quiet && console.error("COOP/COEP Service Worker failed to register:", err);
114
+ }
115
+ );
116
+ }
117
+ })();
118
+ }
trigo-web/yarn.lock CHANGED
@@ -584,6 +584,11 @@ cliui@^9.0.1:
584
  strip-ansi "^7.1.0"
585
  wrap-ansi "^9.0.0"
586
 
 
 
 
 
 
587
  color-convert@^2.0.1:
588
  version "2.0.1"
589
  resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
 
584
  strip-ansi "^7.1.0"
585
  wrap-ansi "^9.0.0"
586
 
587
+ coi-serviceworker@^0.1.7:
588
+ version "0.1.7"
589
+ resolved "https://registry.npmjs.org/coi-serviceworker/-/coi-serviceworker-0.1.7.tgz"
590
+ integrity sha512-bjSUqEngCPOkErY2vbyWsaIGCNRODYzlNycaREVw5s12/C8SM+RnRUUeX6pZbTtov6C52ZLY/+tvHK+BDxuUuA==
591
+
592
  color-convert@^2.0.1:
593
  version "2.0.1"
594
  resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"