cursedbelt-server 4.43.2 → 4.43.3
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.
|
@@ -116,6 +116,19 @@ export declare const WEB_ANALYTICS_PUBLIC_HOST = "cursedalchemy.com";
|
|
|
116
116
|
* production `dist` served from `127.0.0.1`, so a production-only injection is still a console
|
|
117
117
|
* error there. The hostname is the honest discriminator, not the build mode.
|
|
118
118
|
*
|
|
119
|
+
* ## 🔴 Why it is skipped on a GET-only (ctgr) device
|
|
120
|
+
*
|
|
121
|
+
* A device in GET-only mode (`cursedbelt-core/ctgr-client`) sits behind something that drops
|
|
122
|
+
* every non-GET, and the beacon reports with a POST to the page's `/cdn-cgi/rum`. It cannot be
|
|
123
|
+
* tunnelled the way our own API is — the script is Cloudflare's — so there it only ever failed,
|
|
124
|
+
* a red line per page view, and recorded nothing. Not loading it loses no data (2026-10-08).
|
|
125
|
+
*
|
|
126
|
+
* The guard reads the URL as well as `localStorage.ctgr`: this script runs before the app's
|
|
127
|
+
* `applyCtgrFromLocation()` has stored a first `?ctgr=t`, so the stored flag alone would still
|
|
128
|
+
* fire on the visit that turns the mode on — and `?ctgr=f` must win over a flag about to be
|
|
129
|
+
* cleared. The spellings are `ctgrConfig.ts`'s; `tools/check-web-analytics.ts` EXECUTES every
|
|
130
|
+
* shell's copy against them.
|
|
131
|
+
*
|
|
119
132
|
* 🔴 It needs inline script to be permitted on the page. Every shell that carries it already
|
|
120
133
|
* ships one; `apps/vault` does not, serves `script-src 'self'`, and is exempt from the beacon
|
|
121
134
|
* for that reason — see `tools/check-web-analytics.ts`.
|
|
@@ -123,6 +123,19 @@ export const WEB_ANALYTICS_PUBLIC_HOST = "cursedalchemy.com";
|
|
|
123
123
|
* production `dist` served from `127.0.0.1`, so a production-only injection is still a console
|
|
124
124
|
* error there. The hostname is the honest discriminator, not the build mode.
|
|
125
125
|
*
|
|
126
|
+
* ## 🔴 Why it is skipped on a GET-only (ctgr) device
|
|
127
|
+
*
|
|
128
|
+
* A device in GET-only mode (`cursedbelt-core/ctgr-client`) sits behind something that drops
|
|
129
|
+
* every non-GET, and the beacon reports with a POST to the page's `/cdn-cgi/rum`. It cannot be
|
|
130
|
+
* tunnelled the way our own API is — the script is Cloudflare's — so there it only ever failed,
|
|
131
|
+
* a red line per page view, and recorded nothing. Not loading it loses no data (2026-10-08).
|
|
132
|
+
*
|
|
133
|
+
* The guard reads the URL as well as `localStorage.ctgr`: this script runs before the app's
|
|
134
|
+
* `applyCtgrFromLocation()` has stored a first `?ctgr=t`, so the stored flag alone would still
|
|
135
|
+
* fire on the visit that turns the mode on — and `?ctgr=f` must win over a flag about to be
|
|
136
|
+
* cleared. The spellings are `ctgrConfig.ts`'s; `tools/check-web-analytics.ts` EXECUTES every
|
|
137
|
+
* shell's copy against them.
|
|
138
|
+
*
|
|
126
139
|
* 🔴 It needs inline script to be permitted on the page. Every shell that carries it already
|
|
127
140
|
* ships one; `apps/vault` does not, serves `script-src 'self'`, and is exempt from the beacon
|
|
128
141
|
* for that reason — see `tools/check-web-analytics.ts`.
|
|
@@ -131,7 +144,13 @@ export function webAnalyticsBootstrap(token = WEB_ANALYTICS_SITE_TOKEN) {
|
|
|
131
144
|
return [
|
|
132
145
|
"<script>",
|
|
133
146
|
`\tvar host = location.hostname;`,
|
|
134
|
-
`\
|
|
147
|
+
`\tvar asked = "";`,
|
|
148
|
+
"\tvar getOnly = false;",
|
|
149
|
+
"\ttry {",
|
|
150
|
+
`\t\tasked = ((/[?&]ctgr=([^&]*)/.exec(location.search) || [])[1] || "").toLowerCase();`,
|
|
151
|
+
`\t\tgetOnly = /^(t|on|1|yes|true)$/.test(asked) || (!/^(f|off|0|no|false)$/.test(asked) && localStorage.getItem("ctgr") === "on");`,
|
|
152
|
+
"\t} catch (_e) {}",
|
|
153
|
+
`\tif (!getOnly && (host === "${WEB_ANALYTICS_PUBLIC_HOST}" || host.endsWith(".${WEB_ANALYTICS_PUBLIC_HOST}"))) {`,
|
|
135
154
|
`\t\tvar beacon = document.createElement("script");`,
|
|
136
155
|
`\t\tbeacon.type = "module";`,
|
|
137
156
|
`\t\tbeacon.src = "${WEB_ANALYTICS_BEACON_SRC}";`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedbelt-server",
|
|
3
|
-
"version": "4.43.
|
|
3
|
+
"version": "4.43.3",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The app-facing Bun/Hono server tier of the cursedbelt split — storage, sharing, activity, guard, sync. React-free; cursedbelt-core below it.",
|
|
@@ -70,7 +70,10 @@ describe("the fleet's beacon", () => {
|
|
|
70
70
|
* only shows up at a particular hostname — so a test that merely asserted the string contains
|
|
71
71
|
* "cursedalchemy.com" would pass on a guard with the condition inverted.
|
|
72
72
|
*/
|
|
73
|
-
function runBootstrap(
|
|
73
|
+
function runBootstrap(
|
|
74
|
+
hostname: string,
|
|
75
|
+
device: { search?: string; stored?: string | null; storageThrows?: boolean } = {},
|
|
76
|
+
): { appended: string[]; attrs: Record<string, string> } {
|
|
74
77
|
const body = /<script>([\s\S]*)<\/script>/.exec(webAnalyticsBootstrap())?.[1] ?? "";
|
|
75
78
|
expect(body.trim().length).toBeGreaterThan(0);
|
|
76
79
|
const appended: string[] = [];
|
|
@@ -89,7 +92,13 @@ function runBootstrap(hostname: string): { appended: string[]; attrs: Record<str
|
|
|
89
92
|
},
|
|
90
93
|
},
|
|
91
94
|
};
|
|
92
|
-
|
|
95
|
+
const fakeStorage = {
|
|
96
|
+
getItem(key: string): string | null {
|
|
97
|
+
if (device.storageThrows) throw new Error("SecurityError");
|
|
98
|
+
return key === "ctgr" ? (device.stored ?? null) : null;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
new Function("location", "document", "localStorage", body)({ hostname, search: device.search ?? "" }, fakeDocument, fakeStorage);
|
|
93
102
|
return { appended, attrs };
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -121,6 +130,40 @@ describe("the hostname guard", () => {
|
|
|
121
130
|
});
|
|
122
131
|
});
|
|
123
132
|
|
|
133
|
+
/**
|
|
134
|
+
* 🔴 A GET-only device drops the beacon's POST, so the beacon is not loaded there at all — and
|
|
135
|
+
* the URL counts as well as the stored flag, because this script runs before the app stores it.
|
|
136
|
+
*/
|
|
137
|
+
describe("the GET-only (ctgr) guard", () => {
|
|
138
|
+
const zone = "desk.cursedalchemy.com";
|
|
139
|
+
|
|
140
|
+
test("loads NOTHING on a device whose stored mode is on", () => {
|
|
141
|
+
expect(runBootstrap(zone, { stored: "on" }).appended).toEqual([]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("loads NOTHING on the very visit that turns the mode on — before anything is stored", () => {
|
|
145
|
+
for (const search of ["?ctgr=t", "?ctgr=on", "?ctgr=1", "?ctgr=yes", "?ctgr=TRUE", "?open=sheet:1&ctgr=t"]) {
|
|
146
|
+
expect(runBootstrap(zone, { search }).appended, search).toEqual([]);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("`?ctgr=f` wins over a stored flag the app is about to clear", () => {
|
|
151
|
+
for (const search of ["?ctgr=f", "?ctgr=off", "?ctgr=0", "?a=1&ctgr=no"]) {
|
|
152
|
+
expect(runBootstrap(zone, { search, stored: "on" }).appended, search).toEqual([WEB_ANALYTICS_BEACON_SRC]);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("an ordinary visitor still gets the beacon — an unknown value, another key, or storage that throws", () => {
|
|
157
|
+
for (const device of [{ search: "?ctgr=maybe" }, { search: "?notctgr=t" }, { stored: "off" }, { storageThrows: true }, {}]) {
|
|
158
|
+
expect(runBootstrap(zone, device).appended, JSON.stringify(device)).toEqual([WEB_ANALYTICS_BEACON_SRC]);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("turned on by the URL, it holds even where storage throws", () => {
|
|
163
|
+
expect(runBootstrap(zone, { search: "?ctgr=t", storageThrows: true }).appended).toEqual([]);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
124
167
|
describe("htmlCarriesWebAnalytics", () => {
|
|
125
168
|
test("true for the bootstrap block a shell actually pastes", () => {
|
|
126
169
|
expect(htmlCarriesWebAnalytics(webAnalyticsBootstrap())).toBe(true);
|
|
@@ -135,6 +135,19 @@ export const WEB_ANALYTICS_PUBLIC_HOST = "cursedalchemy.com";
|
|
|
135
135
|
* production `dist` served from `127.0.0.1`, so a production-only injection is still a console
|
|
136
136
|
* error there. The hostname is the honest discriminator, not the build mode.
|
|
137
137
|
*
|
|
138
|
+
* ## 🔴 Why it is skipped on a GET-only (ctgr) device
|
|
139
|
+
*
|
|
140
|
+
* A device in GET-only mode (`cursedbelt-core/ctgr-client`) sits behind something that drops
|
|
141
|
+
* every non-GET, and the beacon reports with a POST to the page's `/cdn-cgi/rum`. It cannot be
|
|
142
|
+
* tunnelled the way our own API is — the script is Cloudflare's — so there it only ever failed,
|
|
143
|
+
* a red line per page view, and recorded nothing. Not loading it loses no data (2026-10-08).
|
|
144
|
+
*
|
|
145
|
+
* The guard reads the URL as well as `localStorage.ctgr`: this script runs before the app's
|
|
146
|
+
* `applyCtgrFromLocation()` has stored a first `?ctgr=t`, so the stored flag alone would still
|
|
147
|
+
* fire on the visit that turns the mode on — and `?ctgr=f` must win over a flag about to be
|
|
148
|
+
* cleared. The spellings are `ctgrConfig.ts`'s; `tools/check-web-analytics.ts` EXECUTES every
|
|
149
|
+
* shell's copy against them.
|
|
150
|
+
*
|
|
138
151
|
* 🔴 It needs inline script to be permitted on the page. Every shell that carries it already
|
|
139
152
|
* ships one; `apps/vault` does not, serves `script-src 'self'`, and is exempt from the beacon
|
|
140
153
|
* for that reason — see `tools/check-web-analytics.ts`.
|
|
@@ -143,7 +156,13 @@ export function webAnalyticsBootstrap(token: string = WEB_ANALYTICS_SITE_TOKEN):
|
|
|
143
156
|
return [
|
|
144
157
|
"<script>",
|
|
145
158
|
`\tvar host = location.hostname;`,
|
|
146
|
-
`\
|
|
159
|
+
`\tvar asked = "";`,
|
|
160
|
+
"\tvar getOnly = false;",
|
|
161
|
+
"\ttry {",
|
|
162
|
+
`\t\tasked = ((/[?&]ctgr=([^&]*)/.exec(location.search) || [])[1] || "").toLowerCase();`,
|
|
163
|
+
`\t\tgetOnly = /^(t|on|1|yes|true)$/.test(asked) || (!/^(f|off|0|no|false)$/.test(asked) && localStorage.getItem("ctgr") === "on");`,
|
|
164
|
+
"\t} catch (_e) {}",
|
|
165
|
+
`\tif (!getOnly && (host === "${WEB_ANALYTICS_PUBLIC_HOST}" || host.endsWith(".${WEB_ANALYTICS_PUBLIC_HOST}"))) {`,
|
|
147
166
|
`\t\tvar beacon = document.createElement("script");`,
|
|
148
167
|
`\t\tbeacon.type = "module";`,
|
|
149
168
|
`\t\tbeacon.src = "${WEB_ANALYTICS_BEACON_SRC}";`,
|