@prosopo/client-bundle-example 2.10.23 → 2.11.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.
Files changed (51) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +5 -4
  2. package/.turbo/turbo-build$colon$tsc.log +11 -11
  3. package/.turbo/turbo-build.log +6 -5
  4. package/CHANGELOG.md +21 -0
  5. package/dist/cjs/index.cjs +13 -41
  6. package/dist/cjs/plugins/pages.cjs +113 -0
  7. package/dist/index.js +2 -42
  8. package/dist/plugins/pages.js +103 -0
  9. package/package.json +7 -7
  10. package/src/frictionless-explicit-web3.html +10 -23
  11. package/src/frictionless-explicit.html +18 -22
  12. package/src/frictionless-implicit.html +60 -86
  13. package/src/frictionless-manual-start.html +13 -33
  14. package/src/image-explicit-web3.html +8 -24
  15. package/src/image-explicit.html +16 -23
  16. package/src/image-implicit.html +192 -0
  17. package/src/index.html +11 -26
  18. package/src/index.ts +1 -62
  19. package/src/invisible-frictionless-explicit.html +8 -17
  20. package/src/invisible-frictionless-implicit.html +8 -25
  21. package/src/invisible-image-explicit.html +8 -23
  22. package/src/invisible-image-implicit.html +8 -24
  23. package/src/invisible-pow-explicit.html +8 -23
  24. package/src/invisible-pow-implicit.html +9 -21
  25. package/src/invisible-puzzle-explicit.html +8 -23
  26. package/src/invisible-puzzle-implicit.html +9 -21
  27. package/src/plugins/code-snippet-injector.ts +179 -0
  28. package/src/plugins/form-filler-injector.ts +36 -121
  29. package/src/plugins/layout-injector.ts +238 -0
  30. package/src/plugins/logo.ts +15 -0
  31. package/src/plugins/pages.ts +219 -0
  32. package/src/plugins/placement-injector.ts +114 -0
  33. package/src/plugins/slots.ts +32 -0
  34. package/src/plugins/status-log-injector.ts +35 -114
  35. package/src/pow-explicit-web3.html +8 -24
  36. package/src/pow-explicit.html +8 -23
  37. package/src/pow-implicit-sessionid.html +10 -24
  38. package/src/pow-implicit.html +9 -24
  39. package/src/puzzle-bind-explicit.html +83 -0
  40. package/src/puzzle-explicit.html +16 -23
  41. package/src/puzzle-implicit.html +9 -24
  42. package/src/styles/demo.css +803 -0
  43. package/src/tests/plugins.unit.test.ts +285 -118
  44. package/tsconfig.tsbuildinfo +1 -1
  45. package/vite.config.ts +11 -5
  46. package/src/plugins/explanation-injector.ts +0 -294
  47. package/src/plugins/navigation-injector.ts +0 -605
  48. package/src/styles/captcha.css +0 -78
  49. package/src/styles/field.css +0 -12
  50. package/src/tests/floatLabel.unit.test.ts +0 -195
  51. package/src/tests/floatLabelReady.unit.test.ts +0 -36
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/client-bundle-example@2.10.23 build:cjs
2
+ > @prosopo/client-bundle-example@2.11.0 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -27,9 +27,10 @@ ViteCommonJSConfig: .
27
27
  vite v8.1.5 building ssr environment for production...
28
28
  Bundle build started
29
29
  
30
- 2 modules transformed.
30
+ 3 modules transformed.
31
31
  rendering chunks...
32
32
  computing gzip size...
33
- dist/cjs/index.cjs 1.41 kB │ gzip: 0.64 kB
33
+ dist/cjs/index.cjs 0.71 kB │ gzip: 0.27 kB
34
+ dist/cjs/plugins/pages.cjs 4.63 kB │ gzip: 1.20 kB
34
35
 
35
- ✓ built in 54ms
36
+ ✓ built in 55ms
@@ -1,8 +1,8 @@
1
1
 
2
- > @prosopo/client-bundle-example@2.10.23 build:tsc
2
+ > @prosopo/client-bundle-example@2.11.0 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 10:39:18 PM - Projects in this build:
5
+ 2:42:19 PM - 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
- 10:39:18 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/vite/NodejsPolarsNativeFilePlugin.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
15
+ 2:42:19 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
16
16
 
17
- 10:39:18 PM - Project '../../packages/util/tsconfig.json' is up to date because newest input '../../packages/util/src/url.ts' is older than output '../../packages/util/tsconfig.tsbuildinfo'
17
+ 2:42:19 PM - Project '../../packages/util/tsconfig.json' is up to date because newest input '../../packages/util/src/url.ts' is older than output '../../packages/util/tsconfig.tsbuildinfo'
18
18
 
19
- 10:39:18 PM - Project '../../packages/logger/tsconfig.json' is up to date because newest input '../../packages/logger/src/logger.ts' is older than output '../../packages/logger/tsconfig.tsbuildinfo'
19
+ 2:42:19 PM - Project '../../packages/logger/tsconfig.json' is up to date because newest input '../../packages/logger/src/index.ts' is older than output '../../packages/logger/tsconfig.tsbuildinfo'
20
20
 
21
- 10:39:18 PM - Project '../../packages/dotenv/tsconfig.json' is up to date because newest input '../../packages/dotenv/src/env.ts' is older than output '../../packages/dotenv/tsconfig.tsbuildinfo'
21
+ 2:42:19 PM - Project '../../packages/dotenv/tsconfig.json' is up to date because newest input '../../packages/dotenv/src/tests/env.unit.test.ts' is older than output '../../packages/dotenv/tsconfig.tsbuildinfo'
22
22
 
23
- 10:39:18 PM - Project '../../packages/locale/tsconfig.json' is up to date because newest input '../../packages/locale/src/translationKey.ts' is older than output '../../packages/locale/tsconfig.tsbuildinfo'
23
+ 2:42:19 PM - Project '../../packages/locale/tsconfig.json' is up to date because newest input '../../packages/locale/src/translationKey.ts' is older than output '../../packages/locale/tsconfig.tsbuildinfo'
24
24
 
25
- 10:39:18 PM - 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'
25
+ 2:42:19 PM - 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
- 10:39:18 PM - 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'
27
+ 2:42:19 PM - 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
- 10:39:18 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
29
+ 2:42:19 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
30
30
 
31
- 10:39:18 PM - Building project '/home/runner/work/captcha/captcha/demos/client-bundle-example/tsconfig.json'...
31
+ 2:42:19 PM - Building project '/home/runner/work/captcha/captcha/demos/client-bundle-example/tsconfig.json'...
32
32
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/client-bundle-example@2.10.23 build
2
+ > @prosopo/client-bundle-example@2.11.0 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/client-bundle-example@2.10.23 build:cross-env
6
+ > @prosopo/client-bundle-example@2.11.0 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -31,10 +31,11 @@ ViteEsmConfig: .
31
31
  vite v8.1.5 building ssr environment for production...
32
32
  Bundle build started
33
33
  
34
- 2 modules transformed.
34
+ 3 modules transformed.
35
35
  rendering chunks...
36
36
  computing gzip size...
37
37
  dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
38
- dist/index.js 1.47 kB │ gzip: 0.68 kB
38
+ dist/index.js 0.42 kB │ gzip: 0.19 kB
39
+ dist/plugins/pages.js 4.04 kB │ gzip: 1.15 kB
39
40
 
40
- ✓ built in 79ms
41
+ ✓ built in 151ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @prosopo/client-bundle-example
2
2
 
3
+ ## 2.11.0
4
+ ### Minor Changes
5
+
6
+ - 2256f94: Redesign the demo site as a Prosopo-branded playground. Every demo page now has the prosopo.io header, a sidebar to switch captcha type, mode, rendering and challenge placement, the event log and the code for the current setup side by side, and sign-up links. The home page is now the frictionless captcha instead of the image captcha, which moves to `/image-implicit.html`; the cypress configs that opened the home page for the image captcha now open that page. The MUI stylesheet and the float-label script are gone.
7
+
8
+ ### Patch Changes
9
+
10
+ - 7291d30: Fix the demo pages' status log dropping the captcha token. Its `onActionHandler` wrapper took no arguments, so invisible implicit pages (image and frictionless) called the real handler without a token, showed "Must complete captcha" and never submitted the form.
11
+ - 2fc615d: Restore the `frictionless-implicit.html` demo page.
12
+
13
+ The playground redesign renamed it to `image-implicit.html` and switched it to
14
+ an image site key, which left nothing serving that path. Suites outside this
15
+ repo navigate to it directly and were being answered by the dev server's
16
+ fallback to the index page — which happens to render a frictionless widget, so
17
+ they passed by luck rather than because the page they asked for existed.
18
+
19
+ ## 2.10.24
20
+ ### Patch Changes
21
+
22
+ - f4e4a83: chore(deps): roll up the open dependabot bumps (react 19.3, mongoose 9.10, @polkadot/util 14, redis 6, cron-parser 5, react-i18next 17 with i18next 26, @scure/base 2, cypress 16, rollup/babel plugin majors, vitest 4.1.11, angular 20.3.28, js-yaml)
23
+
3
24
  ## 2.10.23
4
25
  ### Patch Changes
5
26
 
@@ -1,41 +1,13 @@
1
- //#region src/index.ts
2
- (() => {
3
- function whenDOMReady(fn) {
4
- if (document.readyState !== "loading") fn();
5
- else document.addEventListener("DOMContentLoaded", fn);
6
- }
7
- whenDOMReady(() => {
8
- const wrappers = Array.from(document.querySelectorAll(".mui-textfield--float-label"));
9
- for (const wrapper of wrappers) {
10
- const input = wrapper.querySelector("input, textarea, select");
11
- const label = wrapper.querySelector("label");
12
- if (!input || !label) return;
13
- if (!input.getAttribute("aria-label") && label.textContent) input.setAttribute("aria-label", label.textContent.trim());
14
- const update = () => {
15
- const hasValue = input.type === "checkbox" || input.type === "radio" ? input.checked : input.value && input.value.trim() !== "";
16
- if (document.activeElement === input || hasValue) wrapper.classList.add("label-hidden");
17
- else wrapper.classList.remove("label-hidden");
18
- };
19
- for (const evt of [
20
- "focus",
21
- "input",
22
- "blur",
23
- "change",
24
- "keyup",
25
- "paste"
26
- ]) input.addEventListener(evt, update, { passive: true });
27
- update();
28
- }
29
- const maxChecks = 12;
30
- let checks = 0;
31
- const iv = setInterval(() => {
32
- checks++;
33
- for (const w of wrappers) {
34
- const input = w.querySelector("input,textarea,select");
35
- if (input) input.dispatchEvent(new Event("input", { bubbles: true }));
36
- }
37
- if (checks >= maxChecks) clearInterval(iv);
38
- }, 250);
39
- });
40
- })();
41
- //#endregion
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_pages = require("./plugins/pages.cjs");
3
+ exports.captchaTypeOptions = require_pages.captchaTypeOptions;
4
+ exports.defaultSetup = require_pages.defaultSetup;
5
+ exports.demoPages = require_pages.demoPages;
6
+ exports.findPageByPath = require_pages.findPageByPath;
7
+ exports.labelOf = require_pages.labelOf;
8
+ exports.modeOptions = require_pages.modeOptions;
9
+ exports.pagePathFromFilename = require_pages.pagePathFromFilename;
10
+ exports.relativePrefix = require_pages.relativePrefix;
11
+ exports.renderingOptions = require_pages.renderingOptions;
12
+ exports.renderingsFor = require_pages.renderingsFor;
13
+ exports.resolvePage = require_pages.resolvePage;
@@ -0,0 +1,113 @@
1
+ let _prosopo_types = require("@prosopo/types");
2
+ //#region src/plugins/pages.ts
3
+ var captchaTypeOptions = [
4
+ {
5
+ value: _prosopo_types.CaptchaType.frictionless,
6
+ label: "Frictionless",
7
+ description: "Humans pass without a challenge. Bots get one."
8
+ },
9
+ {
10
+ value: _prosopo_types.CaptchaType.pow,
11
+ label: "Proof of Work",
12
+ description: "The browser does a quick computation."
13
+ },
14
+ {
15
+ value: _prosopo_types.CaptchaType.puzzle,
16
+ label: "Puzzle",
17
+ description: "Drag a piece into place."
18
+ },
19
+ {
20
+ value: _prosopo_types.CaptchaType.image,
21
+ label: "Image",
22
+ description: "Pick the images that match."
23
+ }
24
+ ];
25
+ var modeOptions = [{
26
+ value: "standard",
27
+ label: "Standard"
28
+ }, {
29
+ value: "invisible",
30
+ label: "Invisible"
31
+ }];
32
+ var renderingOptions = [
33
+ {
34
+ value: "implicit",
35
+ label: "Implicit",
36
+ description: "Add a div with your site key and the script renders the widget."
37
+ },
38
+ {
39
+ value: "explicit",
40
+ label: "Explicit",
41
+ description: "Your own code calls render() when it is ready."
42
+ },
43
+ {
44
+ value: "manual",
45
+ label: "Manual start",
46
+ description: "The widget shows straight away, but checks only start when you say."
47
+ },
48
+ {
49
+ value: "bound",
50
+ label: "Bound button",
51
+ description: "Your own submit button opens the challenge."
52
+ }
53
+ ];
54
+ var page = (path, captchaType, mode, rendering) => ({
55
+ path,
56
+ captchaType,
57
+ mode,
58
+ rendering
59
+ });
60
+ var indexPage = page("index.html", _prosopo_types.CaptchaType.frictionless, "standard", "implicit");
61
+ var defaultSetup = indexPage;
62
+ var demoPages = [
63
+ indexPage,
64
+ page("frictionless-explicit.html", _prosopo_types.CaptchaType.frictionless, "standard", "explicit"),
65
+ page("frictionless-manual-start.html", _prosopo_types.CaptchaType.frictionless, "standard", "manual"),
66
+ page("invisible-frictionless-implicit.html", _prosopo_types.CaptchaType.frictionless, "invisible", "implicit"),
67
+ page("invisible-frictionless-explicit.html", _prosopo_types.CaptchaType.frictionless, "invisible", "explicit"),
68
+ page("pow-implicit.html", _prosopo_types.CaptchaType.pow, "standard", "implicit"),
69
+ page("pow-explicit.html", _prosopo_types.CaptchaType.pow, "standard", "explicit"),
70
+ page("invisible-pow-implicit.html", _prosopo_types.CaptchaType.pow, "invisible", "implicit"),
71
+ page("invisible-pow-explicit.html", _prosopo_types.CaptchaType.pow, "invisible", "explicit"),
72
+ page("puzzle-implicit.html", _prosopo_types.CaptchaType.puzzle, "standard", "implicit"),
73
+ page("puzzle-explicit.html", _prosopo_types.CaptchaType.puzzle, "standard", "explicit"),
74
+ page("puzzle-bind-explicit.html", _prosopo_types.CaptchaType.puzzle, "standard", "bound"),
75
+ page("invisible-puzzle-implicit.html", _prosopo_types.CaptchaType.puzzle, "invisible", "implicit"),
76
+ page("invisible-puzzle-explicit.html", _prosopo_types.CaptchaType.puzzle, "invisible", "explicit"),
77
+ page("image-implicit.html", _prosopo_types.CaptchaType.image, "standard", "implicit"),
78
+ page("image-explicit.html", _prosopo_types.CaptchaType.image, "standard", "explicit"),
79
+ page("invisible-image-implicit.html", _prosopo_types.CaptchaType.image, "invisible", "implicit"),
80
+ page("invisible-image-explicit.html", _prosopo_types.CaptchaType.image, "invisible", "explicit")
81
+ ];
82
+ var isSetup = (candidate, setup) => candidate.captchaType === setup.captchaType && candidate.mode === setup.mode && candidate.rendering === setup.rendering;
83
+ var findPageByPath = (path) => demoPages.find((demoPage) => demoPage.path === path);
84
+ var resolvePage = (setup) => demoPages.find((demoPage) => isSetup(demoPage, setup)) ?? demoPages.find((demoPage) => isSetup(demoPage, {
85
+ ...setup,
86
+ rendering: "implicit"
87
+ })) ?? demoPages.find((demoPage) => isSetup(demoPage, {
88
+ ...setup,
89
+ mode: "standard",
90
+ rendering: "implicit"
91
+ })) ?? indexPage;
92
+ var renderingsFor = (captchaType, mode) => renderingOptions.filter(({ value }) => demoPages.some((demoPage) => isSetup(demoPage, {
93
+ captchaType,
94
+ mode,
95
+ rendering: value
96
+ })));
97
+ var labelOf = (options, value) => options.find((option) => option.value === value)?.label ?? String(value);
98
+ var pagePathFromFilename = (filename) => {
99
+ return (filename ?? "").replace(/\\/g, "/").match(/^(?:.*\/)?(?:src|dist)\/(.+)$/)?.[1] ?? "";
100
+ };
101
+ var relativePrefix = (pagePath) => "../".repeat((pagePath.match(/\//g) ?? []).length);
102
+ //#endregion
103
+ exports.captchaTypeOptions = captchaTypeOptions;
104
+ exports.defaultSetup = defaultSetup;
105
+ exports.demoPages = demoPages;
106
+ exports.findPageByPath = findPageByPath;
107
+ exports.labelOf = labelOf;
108
+ exports.modeOptions = modeOptions;
109
+ exports.pagePathFromFilename = pagePathFromFilename;
110
+ exports.relativePrefix = relativePrefix;
111
+ exports.renderingOptions = renderingOptions;
112
+ exports.renderingsFor = renderingsFor;
113
+ exports.resolvePage = resolvePage;
package/dist/index.js CHANGED
@@ -1,43 +1,3 @@
1
1
  import "./_virtual/_rolldown/runtime.js";
2
- //#region src/index.ts
3
- (() => {
4
- function whenDOMReady(fn) {
5
- if (document.readyState !== "loading") fn();
6
- else document.addEventListener("DOMContentLoaded", fn);
7
- }
8
- whenDOMReady(() => {
9
- const wrappers = Array.from(document.querySelectorAll(".mui-textfield--float-label"));
10
- for (const wrapper of wrappers) {
11
- const input = wrapper.querySelector("input, textarea, select");
12
- const label = wrapper.querySelector("label");
13
- if (!input || !label) return;
14
- if (!input.getAttribute("aria-label") && label.textContent) input.setAttribute("aria-label", label.textContent.trim());
15
- const update = () => {
16
- const hasValue = input.type === "checkbox" || input.type === "radio" ? input.checked : input.value && input.value.trim() !== "";
17
- if (document.activeElement === input || hasValue) wrapper.classList.add("label-hidden");
18
- else wrapper.classList.remove("label-hidden");
19
- };
20
- for (const evt of [
21
- "focus",
22
- "input",
23
- "blur",
24
- "change",
25
- "keyup",
26
- "paste"
27
- ]) input.addEventListener(evt, update, { passive: true });
28
- update();
29
- }
30
- const maxChecks = 12;
31
- let checks = 0;
32
- const iv = setInterval(() => {
33
- checks++;
34
- for (const w of wrappers) {
35
- const input = w.querySelector("input,textarea,select");
36
- if (input) input.dispatchEvent(new Event("input", { bubbles: true }));
37
- }
38
- if (checks >= maxChecks) clearInterval(iv);
39
- }, 250);
40
- });
41
- })();
42
- //#endregion
43
- export {};
2
+ import { captchaTypeOptions, defaultSetup, demoPages, findPageByPath, labelOf, modeOptions, pagePathFromFilename, relativePrefix, renderingOptions, renderingsFor, resolvePage } from "./plugins/pages.js";
3
+ export { captchaTypeOptions, defaultSetup, demoPages, findPageByPath, labelOf, modeOptions, pagePathFromFilename, relativePrefix, renderingOptions, renderingsFor, resolvePage };
@@ -0,0 +1,103 @@
1
+ import { CaptchaType } from "@prosopo/types";
2
+ //#region src/plugins/pages.ts
3
+ var captchaTypeOptions = [
4
+ {
5
+ value: CaptchaType.frictionless,
6
+ label: "Frictionless",
7
+ description: "Humans pass without a challenge. Bots get one."
8
+ },
9
+ {
10
+ value: CaptchaType.pow,
11
+ label: "Proof of Work",
12
+ description: "The browser does a quick computation."
13
+ },
14
+ {
15
+ value: CaptchaType.puzzle,
16
+ label: "Puzzle",
17
+ description: "Drag a piece into place."
18
+ },
19
+ {
20
+ value: CaptchaType.image,
21
+ label: "Image",
22
+ description: "Pick the images that match."
23
+ }
24
+ ];
25
+ var modeOptions = [{
26
+ value: "standard",
27
+ label: "Standard"
28
+ }, {
29
+ value: "invisible",
30
+ label: "Invisible"
31
+ }];
32
+ var renderingOptions = [
33
+ {
34
+ value: "implicit",
35
+ label: "Implicit",
36
+ description: "Add a div with your site key and the script renders the widget."
37
+ },
38
+ {
39
+ value: "explicit",
40
+ label: "Explicit",
41
+ description: "Your own code calls render() when it is ready."
42
+ },
43
+ {
44
+ value: "manual",
45
+ label: "Manual start",
46
+ description: "The widget shows straight away, but checks only start when you say."
47
+ },
48
+ {
49
+ value: "bound",
50
+ label: "Bound button",
51
+ description: "Your own submit button opens the challenge."
52
+ }
53
+ ];
54
+ var page = (path, captchaType, mode, rendering) => ({
55
+ path,
56
+ captchaType,
57
+ mode,
58
+ rendering
59
+ });
60
+ var indexPage = page("index.html", CaptchaType.frictionless, "standard", "implicit");
61
+ var defaultSetup = indexPage;
62
+ var demoPages = [
63
+ indexPage,
64
+ page("frictionless-explicit.html", CaptchaType.frictionless, "standard", "explicit"),
65
+ page("frictionless-manual-start.html", CaptchaType.frictionless, "standard", "manual"),
66
+ page("invisible-frictionless-implicit.html", CaptchaType.frictionless, "invisible", "implicit"),
67
+ page("invisible-frictionless-explicit.html", CaptchaType.frictionless, "invisible", "explicit"),
68
+ page("pow-implicit.html", CaptchaType.pow, "standard", "implicit"),
69
+ page("pow-explicit.html", CaptchaType.pow, "standard", "explicit"),
70
+ page("invisible-pow-implicit.html", CaptchaType.pow, "invisible", "implicit"),
71
+ page("invisible-pow-explicit.html", CaptchaType.pow, "invisible", "explicit"),
72
+ page("puzzle-implicit.html", CaptchaType.puzzle, "standard", "implicit"),
73
+ page("puzzle-explicit.html", CaptchaType.puzzle, "standard", "explicit"),
74
+ page("puzzle-bind-explicit.html", CaptchaType.puzzle, "standard", "bound"),
75
+ page("invisible-puzzle-implicit.html", CaptchaType.puzzle, "invisible", "implicit"),
76
+ page("invisible-puzzle-explicit.html", CaptchaType.puzzle, "invisible", "explicit"),
77
+ page("image-implicit.html", CaptchaType.image, "standard", "implicit"),
78
+ page("image-explicit.html", CaptchaType.image, "standard", "explicit"),
79
+ page("invisible-image-implicit.html", CaptchaType.image, "invisible", "implicit"),
80
+ page("invisible-image-explicit.html", CaptchaType.image, "invisible", "explicit")
81
+ ];
82
+ var isSetup = (candidate, setup) => candidate.captchaType === setup.captchaType && candidate.mode === setup.mode && candidate.rendering === setup.rendering;
83
+ var findPageByPath = (path) => demoPages.find((demoPage) => demoPage.path === path);
84
+ var resolvePage = (setup) => demoPages.find((demoPage) => isSetup(demoPage, setup)) ?? demoPages.find((demoPage) => isSetup(demoPage, {
85
+ ...setup,
86
+ rendering: "implicit"
87
+ })) ?? demoPages.find((demoPage) => isSetup(demoPage, {
88
+ ...setup,
89
+ mode: "standard",
90
+ rendering: "implicit"
91
+ })) ?? indexPage;
92
+ var renderingsFor = (captchaType, mode) => renderingOptions.filter(({ value }) => demoPages.some((demoPage) => isSetup(demoPage, {
93
+ captchaType,
94
+ mode,
95
+ rendering: value
96
+ })));
97
+ var labelOf = (options, value) => options.find((option) => option.value === value)?.label ?? String(value);
98
+ var pagePathFromFilename = (filename) => {
99
+ return (filename ?? "").replace(/\\/g, "/").match(/^(?:.*\/)?(?:src|dist)\/(.+)$/)?.[1] ?? "";
100
+ };
101
+ var relativePrefix = (pagePath) => "../".repeat((pagePath.match(/\//g) ?? []).length);
102
+ //#endregion
103
+ export { captchaTypeOptions, defaultSetup, demoPages, findPageByPath, labelOf, modeOptions, pagePathFromFilename, relativePrefix, renderingOptions, renderingsFor, resolvePage };
package/package.json CHANGED
@@ -25,21 +25,21 @@
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.10.23",
28
+ "version": "2.11.0",
29
29
  "devDependencies": {
30
30
  "@emotion/cache": "11.14.0",
31
- "@prosopo/config": "3.3.13",
32
- "@prosopo/dotenv": "3.0.54",
33
- "@prosopo/locale": "3.4.1",
34
- "@prosopo/types": "5.6.0",
31
+ "@prosopo/config": "3.3.17",
32
+ "@prosopo/dotenv": "3.0.56",
33
+ "@prosopo/locale": "3.4.3",
34
+ "@prosopo/types": "5.9.0",
35
35
  "@types/node": "22.5.5",
36
36
  "@vitest/coverage-v8": "4.1.11",
37
37
  "concurrently": "9.0.1",
38
38
  "del-cli": "6.0.0",
39
39
  "jsdom": "25.0.0",
40
40
  "npm-run-all": "4.1.5",
41
- "react": "19.2.8",
42
- "react-dom": "19.2.8",
41
+ "react": "19.3.0",
42
+ "react-dom": "19.3.0",
43
43
  "tslib": "2.7.0",
44
44
  "tsx": "4.20.3",
45
45
  "typescript": "5.6.2",
@@ -1,12 +1,8 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
- <link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
5
- <link href="styles/field.css" rel="stylesheet" type="text/css"/>
6
4
 
7
- <script src="index.js"></script>
8
- <title>Procaptcha demo: Frictionless CAPTCHA</title>
9
- <link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
5
+ <title>Procaptcha demo: Frictionless, explicit rendering, web3</title>
10
6
  <script type="module">
11
7
  window.onCaptchaFailed = function () {
12
8
  console.log('Challenge failed');
@@ -142,42 +138,34 @@
142
138
  observer.observe(document.body, { childList: true, subtree: true });
143
139
  });
144
140
 
145
- // updateCaptchaStatus is now provided by status-log-injector
146
141
  </script>
147
142
  </head>
148
143
  <body>
149
144
 
150
- <div class="mui-container">
151
- <h1>Frictionless CAPTCHA - Explicit Rendering</h1>
152
- <p>This example demonstrates how to use Procaptcha in frictionless mode with explicit rendering.</p>
145
+ <div class="demo-card">
153
146
 
154
- <!-- CAPTCHA Status Display will be injected by the status-log-injector plugin -->
155
-
156
- <form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="mui-form" id="demo-form">
157
- <h2>Example Login Form</h2>
158
- <div class="mui-textfield mui-textfield--float-label">
147
+ <!-- nosemgrep: python.django.security.django-no-csrf-token.django-no-csrf-token -->
148
+ <form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="demo-form" id="demo-form">
149
+ <h2>Create an account</h2>
150
+ <div class="demo-field">
159
151
  <label for="name">Name</label>
160
152
  <input id="name" type="text" name="name" required/>
161
153
  </div>
162
- <div class="mui-textfield mui-textfield--float-label">
154
+ <div class="demo-field">
163
155
  <label for="email">Email Address</label>
164
156
  <input id="email" type="email" name="email" required/>
165
157
  </div>
166
- <div class="mui-textfield mui-textfield--float-label">
158
+ <div class="demo-field">
167
159
  <label for="password">Password</label>
168
160
  <input id="password" type="password" name="password" required/>
169
161
  </div>
170
- <div class="mui-textfield mui-textfield--float-label">
162
+ <div class="demo-field">
171
163
  <div id="procaptcha-container"></div>
172
164
  </div>
173
165
  <div id="messageContainer" style="display: none; color: black;"><span id="message"></span></div>
174
- <button type="button" class="mui-btn mui-btn--raised" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
166
+ <button type="button" class="demo-button" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
175
167
  </form>
176
168
 
177
- <!-- Console output display area -->
178
- <div id="console-output" class="console-output" style="display: none;"></div>
179
-
180
- <!-- Explanation will be injected by the explanation-injector plugin -->
181
169
  </div>
182
170
  <script type="module">
183
171
  // Pattern to avoid race condition between Procaptcha script loading and Procaptcha render function call
@@ -201,7 +189,6 @@
201
189
  // render a modal and get the user to select 1 account
202
190
  const accountSelect = document.createElement('select');
203
191
  accountSelect.id = 'account-select';
204
- accountSelect.classList.add('mui-select');
205
192
  accountSelect.classList.add('account-select');
206
193
  accounts.forEach((account) => {
207
194
  const option = document.createElement('option');
@@ -1,12 +1,8 @@
1
1
  <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
- <link href="https://cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css"/>
5
- <link href="styles/field.css" rel="stylesheet" type="text/css"/>
6
4
 
7
- <script src="index.js"></script>
8
- <title>Procaptcha demo: Frictionless CAPTCHA</title>
9
- <link href="styles/captcha.css" rel="stylesheet" type="text/css"/>
5
+ <title>Procaptcha demo: Frictionless, explicit rendering</title>
10
6
  <script type="module">
11
7
  window.onCaptchaFailed = function () {
12
8
  console.log('Challenge failed');
@@ -142,42 +138,34 @@
142
138
  observer.observe(document.body, { childList: true, subtree: true });
143
139
  });
144
140
 
145
- // updateCaptchaStatus is now provided by status-log-injector
146
141
  </script>
147
142
  </head>
148
143
  <body>
149
144
 
150
- <div class="mui-container">
151
- <h1>Frictionless CAPTCHA - Explicit Rendering</h1>
152
- <p>This example demonstrates how to use Procaptcha in frictionless mode with explicit rendering.</p>
145
+ <div class="demo-card">
153
146
 
154
- <!-- CAPTCHA Status Display will be injected by the status-log-injector plugin -->
155
-
156
- <form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="mui-form">
157
- <h2>Example Login Form</h2>
158
- <div class="mui-textfield mui-textfield--float-label">
147
+ <!-- nosemgrep: python.django.security.django-no-csrf-token.django-no-csrf-token -->
148
+ <form action="%PROSOPO_SERVER_URL%/signup" method="POST" class="demo-form">
149
+ <h2>Create an account</h2>
150
+ <div class="demo-field">
159
151
  <label for="name">Name</label>
160
152
  <input id="name" type="text" name="name" required/>
161
153
  </div>
162
- <div class="mui-textfield mui-textfield--float-label">
154
+ <div class="demo-field">
163
155
  <label for="email">Email Address</label>
164
156
  <input id="email" type="email" name="email" required/>
165
157
  </div>
166
- <div class="mui-textfield mui-textfield--float-label">
158
+ <div class="demo-field">
167
159
  <label for="password">Password</label>
168
160
  <input id="password" type="password" name="password" required/>
169
161
  </div>
170
- <div class="mui-textfield mui-textfield--float-label">
162
+ <div class="demo-field">
171
163
  <div id="procaptcha-container"></div>
172
164
  </div>
173
165
  <div id="messageContainer" style="display: none; color: black;"><span id="message"></span></div>
174
- <button type="button" class="mui-btn mui-btn--raised" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
166
+ <button type="button" class="demo-button" onclick="onActionHandler()" data-cy="submit-button">Submit</button>
175
167
  </form>
176
168
 
177
- <!-- Console output display area -->
178
- <div id="console-output" class="console-output" style="display: none;"></div>
179
-
180
- <!-- Explanation will be injected by the explanation-injector plugin -->
181
169
  </div>
182
170
  <script type="module">
183
171
  // Pattern to avoid race condition between Procaptcha script loading and Procaptcha render function call
@@ -193,9 +181,17 @@
193
181
  // Get the Element using elementId
194
182
  const captchaContainer = document.getElementById('procaptcha-container');
195
183
 
184
+ // ?placement=float anchors the challenge to the widget; the default is popup.
185
+ const placement =
186
+ new URLSearchParams(window.location.search).get("placement") === "float"
187
+ ? "float"
188
+ : "popup";
189
+ window.updateCaptchaStatus('Challenge placement: ' + placement, 'info');
190
+
196
191
  // Render the CAPTCHA
197
192
  const widgetId = render(captchaContainer, {
198
193
  siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
194
+ placement,
199
195
  callback: onCaptchaVerified,
200
196
  "failed-callback": function () {
201
197
  console.log('Challenge failed');