@prosopo/client-bundle-example 2.11.0 → 2.11.2
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/.turbo/turbo-build$colon$cjs.log +3 -3
- package/.turbo/turbo-build$colon$tsc.log +11 -11
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +10 -0
- package/package.json +5 -5
- package/src/plugins/layout-injector.ts +19 -1
- package/src/plugins/status-log-injector.ts +26 -3
- package/src/tests/plugins.unit.test.ts +68 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/client-bundle-example@2.11.
|
|
2
|
+
> @prosopo/client-bundle-example@2.11.2 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -16,6 +16,7 @@ ViteCommonJSConfig: .
|
|
|
16
16
|
{
|
|
17
17
|
externals: [
|
|
18
18
|
'@prosopo/dotenv',
|
|
19
|
+
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
19
20
|
'@prosopo/logger',
|
|
20
21
|
'@prosopo/util',
|
|
21
22
|
'@prosopo/locale',
|
|
@@ -23,7 +24,6 @@ ViteCommonJSConfig: .
|
|
|
23
24
|
'@prosopo/util-crypto'
|
|
24
25
|
]
|
|
25
26
|
}
|
|
26
|
-
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
27
27
|
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
28
28
|
Bundle build started
|
|
29
29
|
[2K
|
|
@@ -33,4 +33,4 @@ computing gzip size...
|
|
|
33
33
|
dist/cjs/index.cjs 0.71 kB │ gzip: 0.27 kB
|
|
34
34
|
dist/cjs/plugins/pages.cjs 4.63 kB │ gzip: 1.20 kB
|
|
35
35
|
|
|
36
|
-
[32m✓ built in
|
|
36
|
+
[32m✓ built in 60ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/client-bundle-example@2.11.
|
|
2
|
+
> @prosopo/client-bundle-example@2.11.2 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
9:56:19 AM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../../packages/util/tsconfig.json
|
|
8
8
|
* ../../packages/logger/tsconfig.json
|
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
* ../../packages/types/tsconfig.json
|
|
13
13
|
* tsconfig.json
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
9:56:19 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/vite/vite.frontend.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
9:56:19 AM - Project '../../packages/util/tsconfig.json' is up to date because newest input '../../packages/util/src/verifyRecency.ts' is older than output '../../packages/util/tsconfig.tsbuildinfo'
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
9:56:19 AM - Project '../../packages/logger/tsconfig.json' is up to date because newest input '../../packages/logger/src/tests/loggerBrowser.unit.test.ts' is older than output '../../packages/logger/tsconfig.tsbuildinfo'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
9:56:19 AM - Project '../../packages/dotenv/tsconfig.json' is up to date because newest input '../../packages/dotenv/src/index.ts' is older than output '../../packages/dotenv/tsconfig.tsbuildinfo'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
9:56:19 AM - Project '../../packages/locale/tsconfig.json' is up to date because newest input '../../packages/locale/src/util.ts' is older than output '../../packages/locale/tsconfig.tsbuildinfo'
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
9:56:19 AM - Project '../../packages/util-crypto/tsconfig.json' is up to date because newest input '../../packages/util-crypto/src/types.ts' is older than output '../../packages/util-crypto/tsconfig.tsbuildinfo'
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
9:56:20 AM - Project '../../packages/types/tsconfig.json' is up to date because newest input '../../packages/types/src/types.test-d.ts' is older than output '../../packages/types/tsconfig.tsbuildinfo'
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
9:56:20 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
9:56:20 AM - Building project '/home/runner/work/captcha/captcha/demos/client-bundle-example/tsconfig.json'...
|
|
32
32
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/client-bundle-example@2.11.
|
|
2
|
+
> @prosopo/client-bundle-example@2.11.2 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/client-bundle-example@2.11.
|
|
6
|
+
> @prosopo/client-bundle-example@2.11.2 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -38,4 +38,4 @@ dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
|
38
38
|
dist/index.js 0.42 kB │ gzip: 0.19 kB
|
|
39
39
|
dist/plugins/pages.js 4.04 kB │ gzip: 1.15 kB
|
|
40
40
|
|
|
41
|
-
[32m✓ built in
|
|
41
|
+
[32m✓ built in 59ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @prosopo/client-bundle-example
|
|
2
2
|
|
|
3
|
+
## 2.11.2
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- d4c1fa2: Make the explicit-render demo pages show a widget again. The status-log helper was defined in a module script that Vite placed after the page's own entry module, so `window.updateCaptchaStatus(...)` threw at the top of frictionless-, image-, puzzle- and puzzle-bind-explicit before `render()` was called. The helper is now defined by a classic script at the start of `<head>`, and only the callback wrapping stays in a module after the entry.
|
|
7
|
+
|
|
8
|
+
## 2.11.1
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 495c016: The public demo at demo.prosopo.io now reports page views to Plausible under the `demo.prosopo.io` site, so we can see who uses it. The tracker only loads on that exact host, so local runs, staging and the Cypress suite send nothing.
|
|
12
|
+
|
|
3
13
|
## 2.11.0
|
|
4
14
|
### Minor Changes
|
|
5
15
|
|
package/package.json
CHANGED
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"start": "NODE_ENV=${NODE_ENV:-development}; vite serve ./src --port 9232 --config vite.config.ts --mode=$NODE_ENV",
|
|
26
26
|
"test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts"
|
|
27
27
|
},
|
|
28
|
-
"version": "2.11.
|
|
28
|
+
"version": "2.11.2",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@emotion/cache": "11.14.0",
|
|
31
|
-
"@prosopo/config": "3.
|
|
32
|
-
"@prosopo/dotenv": "3.0.
|
|
33
|
-
"@prosopo/locale": "3.
|
|
34
|
-
"@prosopo/types": "5.
|
|
31
|
+
"@prosopo/config": "3.4.2",
|
|
32
|
+
"@prosopo/dotenv": "3.0.58",
|
|
33
|
+
"@prosopo/locale": "3.6.1",
|
|
34
|
+
"@prosopo/types": "5.11.0",
|
|
35
35
|
"@types/node": "22.5.5",
|
|
36
36
|
"@vitest/coverage-v8": "4.1.11",
|
|
37
37
|
"concurrently": "9.0.1",
|
|
@@ -40,13 +40,31 @@ const DOCS_URL = "https://docs.prosopo.io/";
|
|
|
40
40
|
const ariaCurrent = (isCurrent: boolean): string =>
|
|
41
41
|
isCurrent ? ' aria-current="page"' : "";
|
|
42
42
|
|
|
43
|
+
export const DEMO_HOSTNAME = "demo.prosopo.io";
|
|
44
|
+
const PLAUSIBLE_SCRIPT_URL =
|
|
45
|
+
"https://prosopo.io/js/script.kairee5buy1chae8eit0so8ahphae9Oo.js";
|
|
46
|
+
|
|
47
|
+
// Only the public demo reports to Plausible: local runs and the Cypress suite
|
|
48
|
+
// serve these same pages.
|
|
49
|
+
const analyticsTag = `
|
|
50
|
+
<script>
|
|
51
|
+
(function () {
|
|
52
|
+
if (location.hostname !== "${DEMO_HOSTNAME}") return;
|
|
53
|
+
var tracker = document.createElement("script");
|
|
54
|
+
tracker.defer = true;
|
|
55
|
+
tracker.setAttribute("data-domain", "${DEMO_HOSTNAME}");
|
|
56
|
+
tracker.src = "${PLAUSIBLE_SCRIPT_URL}";
|
|
57
|
+
document.head.appendChild(tracker);
|
|
58
|
+
})();
|
|
59
|
+
</script>`;
|
|
60
|
+
|
|
43
61
|
const headTags = (prefix: string): string => `
|
|
44
62
|
<meta charset="utf-8">
|
|
45
63
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
46
64
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
47
65
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
48
66
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700;800&display=swap">
|
|
49
|
-
<link rel="stylesheet" href="${prefix}styles/demo.css"
|
|
67
|
+
<link rel="stylesheet" href="${prefix}styles/demo.css">${analyticsTag}`;
|
|
50
68
|
|
|
51
69
|
const header = `
|
|
52
70
|
<header class="demo-header">
|
|
@@ -17,9 +17,18 @@
|
|
|
17
17
|
import type { IndexHtmlTransformContext, Plugin } from "vite";
|
|
18
18
|
import { fillSlot } from "./slots.js";
|
|
19
19
|
|
|
20
|
+
// Opening tag of <head>, attributes and all.
|
|
21
|
+
const HEAD_OPEN = /<head(\s[^>]*)?>/i;
|
|
22
|
+
|
|
20
23
|
export default function statusLogInjector(): Plugin {
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
// A classic script at the very start of <head>, so it runs during parsing,
|
|
25
|
+
// before any module script. By the time this plugin runs ("post"), Vite has
|
|
26
|
+
// already hoisted the page's own entry module into <head>, and module
|
|
27
|
+
// scripts run in document order: defined in the module below, the helper
|
|
28
|
+
// did not exist yet when the explicit-render pages called it at top level,
|
|
29
|
+
// so they threw before render() and never showed a widget.
|
|
30
|
+
const updateStatusJs = `
|
|
31
|
+
<script>
|
|
23
32
|
function updateCaptchaStatus(message, type = 'info') {
|
|
24
33
|
const statusContainer = document.getElementById('captcha-status');
|
|
25
34
|
if (!statusContainer) return;
|
|
@@ -43,6 +52,14 @@ export default function statusLogInjector(): Plugin {
|
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
window.updateCaptchaStatus = updateCaptchaStatus;
|
|
55
|
+
</script>
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
// A module, after the page's entry module, because it wraps the callbacks
|
|
59
|
+
// that module defines.
|
|
60
|
+
const statusLogJs = `
|
|
61
|
+
<script type="module">
|
|
62
|
+
const updateCaptchaStatus = window.updateCaptchaStatus;
|
|
46
63
|
|
|
47
64
|
// Wrap the page's own callbacks so every page logs the same events.
|
|
48
65
|
const originalOnCaptchaFailed = window.onCaptchaFailed;
|
|
@@ -104,7 +121,13 @@ export default function statusLogInjector(): Plugin {
|
|
|
104
121
|
return html;
|
|
105
122
|
}
|
|
106
123
|
|
|
107
|
-
const
|
|
124
|
+
const withHelper = HEAD_OPEN.test(html)
|
|
125
|
+
? html.replace(HEAD_OPEN, (open) => `${open}${updateStatusJs}`)
|
|
126
|
+
: html;
|
|
127
|
+
const withJs = withHelper.replace(
|
|
128
|
+
"</head>",
|
|
129
|
+
() => `${statusLogJs}</head>`,
|
|
130
|
+
);
|
|
108
131
|
|
|
109
132
|
const inSlot = fillSlot(withJs, "events", statusLogHtml);
|
|
110
133
|
if (inSlot) {
|
|
@@ -24,7 +24,7 @@ import codeSnippetInjector, {
|
|
|
24
24
|
snippetFor,
|
|
25
25
|
} from "../plugins/code-snippet-injector.js";
|
|
26
26
|
import formFillerInjector from "../plugins/form-filler-injector.js";
|
|
27
|
-
import layoutInjector from "../plugins/layout-injector.js";
|
|
27
|
+
import layoutInjector, { DEMO_HOSTNAME } from "../plugins/layout-injector.js";
|
|
28
28
|
import {
|
|
29
29
|
type DemoRendering,
|
|
30
30
|
demoPages,
|
|
@@ -161,6 +161,47 @@ describe("layoutInjector", () => {
|
|
|
161
161
|
);
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
+
it("loads Plausible only when served from the public demo host", () => {
|
|
165
|
+
const html = handler(page(), ctx(`${cwd}/src/pow-explicit.html`));
|
|
166
|
+
const inlineScript = html.match(
|
|
167
|
+
/<script>\s*\(function \(\) \{([\s\S]*?)\}\)\(\);\s*<\/script>/,
|
|
168
|
+
)?.[1];
|
|
169
|
+
expect(inlineScript).toBeDefined();
|
|
170
|
+
|
|
171
|
+
type FakeElement = Record<string, unknown>;
|
|
172
|
+
const loadedFrom = (hostname: string): FakeElement[] => {
|
|
173
|
+
const appended: FakeElement[] = [];
|
|
174
|
+
const fakeDocument = {
|
|
175
|
+
createElement: (): FakeElement => {
|
|
176
|
+
const element: FakeElement = {};
|
|
177
|
+
element.setAttribute = (name: string, value: string): void => {
|
|
178
|
+
element[name] = value;
|
|
179
|
+
};
|
|
180
|
+
return element;
|
|
181
|
+
},
|
|
182
|
+
head: {
|
|
183
|
+
appendChild: (element: FakeElement): void => {
|
|
184
|
+
appended.push(element);
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
new Function("location", "document", inlineScript ?? "")(
|
|
189
|
+
{ hostname },
|
|
190
|
+
fakeDocument,
|
|
191
|
+
);
|
|
192
|
+
return appended;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
expect(loadedFrom("localhost")).toHaveLength(0);
|
|
196
|
+
expect(loadedFrom(`staging.${DEMO_HOSTNAME}`)).toHaveLength(0);
|
|
197
|
+
const [tracker] = loadedFrom(DEMO_HOSTNAME);
|
|
198
|
+
expect(tracker).toMatchObject({
|
|
199
|
+
defer: true,
|
|
200
|
+
"data-domain": DEMO_HOSTNAME,
|
|
201
|
+
src: "https://prosopo.io/js/script.kairee5buy1chae8eit0so8ahphae9Oo.js",
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
164
205
|
it("marks the current type, mode and rendering", () => {
|
|
165
206
|
const html = handler(page(), ctx(`${cwd}/src/pow-explicit.html`));
|
|
166
207
|
|
|
@@ -290,6 +331,32 @@ describe("statusLogInjector", () => {
|
|
|
290
331
|
expect(html).toContain("updateCaptchaStatus");
|
|
291
332
|
});
|
|
292
333
|
|
|
334
|
+
it("defines updateCaptchaStatus before the page's entry module runs", () => {
|
|
335
|
+
// What Vite hands a "post" transform: the entry module already hoisted
|
|
336
|
+
// into <head>. Module scripts run in document order, so the helper must
|
|
337
|
+
// be defined by a classic script ahead of it.
|
|
338
|
+
const built =
|
|
339
|
+
'<html><head><title>demo</title><script type="module" crossorigin src="/assets/entry.js"></script></head><body><p>hi</p></body></html>';
|
|
340
|
+
const html = handler(built, ctx("src/frictionless-explicit.html"));
|
|
341
|
+
|
|
342
|
+
const definedAt = html.indexOf("window.updateCaptchaStatus = ");
|
|
343
|
+
const entryAt = html.indexOf('src="/assets/entry.js"');
|
|
344
|
+
expect(definedAt).toBeGreaterThan(-1);
|
|
345
|
+
expect(definedAt).toBeLessThan(entryAt);
|
|
346
|
+
const definingScript = html.lastIndexOf("<script", definedAt);
|
|
347
|
+
expect(html.slice(definingScript, definedAt)).not.toContain("module");
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("wraps the page callbacks after the page's entry module", () => {
|
|
351
|
+
const built =
|
|
352
|
+
'<html><head><script type="module" src="/assets/entry.js"></script></head><body></body></html>';
|
|
353
|
+
const html = handler(built, ctx("src/image-explicit.html"));
|
|
354
|
+
|
|
355
|
+
expect(html.indexOf("window.onCaptchaFailed = ")).toBeGreaterThan(
|
|
356
|
+
html.indexOf('src="/assets/entry.js"'),
|
|
357
|
+
);
|
|
358
|
+
});
|
|
359
|
+
|
|
293
360
|
it("fills the events slot when the layout provides one", () => {
|
|
294
361
|
const html = handler(
|
|
295
362
|
page(`<form></form>${slotMarkup("events")}`),
|