@prosopo/client-bundle-example 2.11.1 → 2.11.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/client-bundle-example@2.11.1 build:cjs
2
+ > @prosopo/client-bundle-example@2.11.3 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -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
- ✓ built in 66ms
36
+ ✓ built in 52ms
@@ -1,8 +1,8 @@
1
1
 
2
- > @prosopo/client-bundle-example@2.11.1 build:tsc
2
+ > @prosopo/client-bundle-example@2.11.3 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 3:36:52 PM - Projects in this build:
5
+ 12:38:23 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
- 3:36:52 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'
15
+ 12:38:23 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
- 3:36:52 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
+ 12:38:23 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
- 3:36:52 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'
19
+ 12:38:23 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
- 3:36:52 PM - 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'
21
+ 12:38:23 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'
22
22
 
23
- 3:36:52 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
+ 12:38:23 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
- 3:36:52 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
+ 12:38:23 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
- 3:36:52 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
+ 12:38:23 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
- 3:36:52 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
29
+ 12:38:23 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
30
30
 
31
- 3:36:52 PM - Building project '/home/runner/work/captcha/captcha/demos/client-bundle-example/tsconfig.json'...
31
+ 12:38:23 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.11.1 build
2
+ > @prosopo/client-bundle-example@2.11.3 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/client-bundle-example@2.11.1 build:cross-env
6
+ > @prosopo/client-bundle-example@2.11.3 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
- ✓ built in 67ms
41
+ ✓ built in 124ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @prosopo/client-bundle-example
2
2
 
3
+ ## 2.11.3
4
+ ### Patch Changes
5
+
6
+ - 8178ab2: The explicit-render demo pages now wait for `render()` before logging, so they show the real widget id instead of `widget ID: [object Promise]`. The two frictionless explicit pages log the id as well. A test checks that every demo page waits for `render()`.
7
+
8
+ ## 2.11.2
9
+ ### Patch Changes
10
+
11
+ - 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.
12
+
3
13
  ## 2.11.1
4
14
  ### Patch 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.1",
28
+ "version": "2.11.3",
29
29
  "devDependencies": {
30
30
  "@emotion/cache": "11.14.0",
31
- "@prosopo/config": "3.4.1",
32
- "@prosopo/dotenv": "3.0.57",
33
- "@prosopo/locale": "3.6.0",
34
- "@prosopo/types": "5.10.2",
31
+ "@prosopo/config": "3.4.2",
32
+ "@prosopo/dotenv": "3.0.59",
33
+ "@prosopo/locale": "3.6.2",
34
+ "@prosopo/types": "5.12.0",
35
35
  "@types/node": "22.5.5",
36
36
  "@vitest/coverage-v8": "4.1.11",
37
37
  "concurrently": "9.0.1",
@@ -219,7 +219,7 @@
219
219
  const captchaContainer = document.getElementById('procaptcha-container');
220
220
 
221
221
  // Render the CAPTCHA
222
- const widgetId = render(captchaContainer, {
222
+ const widgetId = await render(captchaContainer, {
223
223
  siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
224
224
  callback: onCaptchaVerified,
225
225
  "failed-callback": function () {
@@ -229,6 +229,7 @@
229
229
  web3: true,
230
230
  userAccountAddress: account
231
231
  });
232
+ window.updateCaptchaStatus('CAPTCHA render function called with widget ID: ' + widgetId, 'info');
232
233
  })
233
234
 
234
235
  </script>
@@ -189,7 +189,7 @@
189
189
  window.updateCaptchaStatus('Challenge placement: ' + placement, 'info');
190
190
 
191
191
  // Render the CAPTCHA
192
- const widgetId = render(captchaContainer, {
192
+ const widgetId = await render(captchaContainer, {
193
193
  siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
194
194
  placement,
195
195
  callback: onCaptchaVerified,
@@ -198,6 +198,7 @@
198
198
  window.updateCaptchaStatus('Challenge failed - CAPTCHA verification could not be completed', 'error');
199
199
  }
200
200
  });
201
+ window.updateCaptchaStatus('CAPTCHA render function called with widget ID: ' + widgetId, 'info');
201
202
 
202
203
  </script>
203
204
  </body>
@@ -157,7 +157,7 @@
157
157
 
158
158
  // Render the CAPTCHA
159
159
 
160
- const widgetId = render(document.getElementById('procaptcha-container'), {
160
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
161
161
  siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
162
162
  callback: handleCaptchaResponse,
163
163
  "failed-callback": handleCaptchaFailed,
@@ -116,7 +116,7 @@
116
116
  }
117
117
 
118
118
  // Wait for DOM content to be loaded
119
- document.addEventListener('DOMContentLoaded', function() {
119
+ document.addEventListener('DOMContentLoaded', async function() {
120
120
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
121
121
 
122
122
  // Render the CAPTCHA
@@ -127,7 +127,7 @@
127
127
  : "popup";
128
128
  window.updateCaptchaStatus('Challenge placement: ' + placement, 'info');
129
129
 
130
- const widgetId = render(document.getElementById('procaptcha-container'), {
130
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
131
131
  siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
132
132
  placement,
133
133
  callback: handleCaptchaResponse,
@@ -93,11 +93,11 @@
93
93
  }
94
94
 
95
95
  // Wait for DOM content to be loaded
96
- document.addEventListener('DOMContentLoaded', function() {
96
+ document.addEventListener('DOMContentLoaded', async function() {
97
97
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
98
98
 
99
99
  // Render the CAPTCHA
100
- const widgetId = render(document.getElementById('procaptcha-container'), {
100
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
101
101
  siteKey: import.meta.env.PROSOPO_SITE_KEY_FRICTIONLESS,
102
102
  callback: handleCaptchaResponse,
103
103
  "failed-callback": handleCaptchaFailed,
@@ -117,11 +117,11 @@
117
117
  }
118
118
 
119
119
  // Wait for DOM content to be loaded
120
- document.addEventListener('DOMContentLoaded', function() {
120
+ document.addEventListener('DOMContentLoaded', async function() {
121
121
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
122
122
 
123
123
  // Render the CAPTCHA
124
- const widgetId = render(document.getElementById('procaptcha-container'), {
124
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
125
125
  siteKey: import.meta.env.PROSOPO_SITE_KEY_IMAGE,
126
126
  callback: handleCaptchaResponse,
127
127
  "failed-callback": handleCaptchaFailed,
@@ -117,11 +117,11 @@
117
117
  }
118
118
 
119
119
  // Wait for DOM content to be loaded
120
- document.addEventListener('DOMContentLoaded', function() {
120
+ document.addEventListener('DOMContentLoaded', async function() {
121
121
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
122
122
 
123
123
  // Render the CAPTCHA
124
- const widgetId = render(document.getElementById('procaptcha-container'), {
124
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
125
125
  siteKey: import.meta.env.PROSOPO_SITE_KEY_POW,
126
126
  callback: handleCaptchaResponse,
127
127
  "failed-callback": handleCaptchaFailed,
@@ -116,11 +116,11 @@
116
116
  }
117
117
 
118
118
  // Wait for DOM content to be loaded
119
- document.addEventListener('DOMContentLoaded', function() {
119
+ document.addEventListener('DOMContentLoaded', async function() {
120
120
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
121
121
 
122
122
  // Render the CAPTCHA
123
- const widgetId = render(document.getElementById('procaptcha-container'), {
123
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
124
124
  siteKey: import.meta.env.PROSOPO_SITE_KEY_PUZZLE,
125
125
  callback: handleCaptchaResponse,
126
126
  "failed-callback": handleCaptchaFailed,
@@ -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
- const statusLogJs = `
22
- <script type="module">
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 withJs = html.replace("</head>", () => `${statusLogJs}</head>`);
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) {
@@ -154,7 +154,7 @@
154
154
  // Render the CAPTCHA
155
155
  const account = document.getElementById('account-select') ? document.getElementById('account-select').value : null;
156
156
  window.updateCaptchaStatus(`Rendering the CAPTCHA for account ${account}`, 'info');
157
- const widgetId = render(document.getElementById('procaptcha-container'), {
157
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
158
158
  siteKey: import.meta.env.PROSOPO_SITE_KEY_POW,
159
159
  callback: handleCaptchaResponse,
160
160
  "failed-callback": handleCaptchaFailed,
@@ -116,11 +116,11 @@
116
116
  }
117
117
 
118
118
  // Wait for DOM content to be loaded
119
- document.addEventListener('DOMContentLoaded', function() {
119
+ document.addEventListener('DOMContentLoaded', async function() {
120
120
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
121
121
 
122
122
  // Render the CAPTCHA
123
- const widgetId = render(document.getElementById('procaptcha-container'), {
123
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
124
124
  siteKey: import.meta.env.PROSOPO_SITE_KEY_POW,
125
125
  callback: handleCaptchaResponse,
126
126
  "failed-callback": handleCaptchaFailed
@@ -116,7 +116,7 @@
116
116
  }
117
117
 
118
118
  // Wait for DOM content to be loaded
119
- document.addEventListener('DOMContentLoaded', function() {
119
+ document.addEventListener('DOMContentLoaded', async function() {
120
120
  window.updateCaptchaStatus('Initializing CAPTCHA with explicit render call', 'info');
121
121
 
122
122
  // Render the CAPTCHA
@@ -127,7 +127,7 @@
127
127
  : "popup";
128
128
  window.updateCaptchaStatus('Challenge placement: ' + placement, 'info');
129
129
 
130
- const widgetId = render(document.getElementById('procaptcha-container'), {
130
+ const widgetId = await render(document.getElementById('procaptcha-container'), {
131
131
  siteKey: import.meta.env.PROSOPO_SITE_KEY_PUZZLE,
132
132
  placement,
133
133
  callback: handleCaptchaResponse,
@@ -0,0 +1,49 @@
1
+ // Copyright 2021-2026 Prosopo (UK) Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import fs from "node:fs";
16
+ import path from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { describe, expect, it } from "vitest";
19
+
20
+ // `render()` resolves to the widget id; a demo that uses its return value
21
+ // without awaiting it prints "[object Promise]" instead of the id.
22
+ const srcDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
23
+
24
+ const pagesCallingRender: string[] = fs
25
+ .readdirSync(srcDir)
26
+ .filter((file: string) => file.endsWith(".html"))
27
+ .filter((file: string) =>
28
+ /\brender\(/.test(fs.readFileSync(path.join(srcDir, file), "utf8")),
29
+ );
30
+
31
+ describe("explicit-render demo pages", () => {
32
+ it("finds pages to check", () => {
33
+ expect(pagesCallingRender.length).toBeGreaterThan(0);
34
+ });
35
+
36
+ it.each(pagesCallingRender)("%s awaits render()", (file: string) => {
37
+ const html = fs.readFileSync(path.join(srcDir, file), "utf8");
38
+ const unawaited: string[] = html
39
+ .split("\n")
40
+ .filter(
41
+ (line: string) =>
42
+ /(?<![.\w])render\(/.test(line) &&
43
+ !/await\s+render\(/.test(line) &&
44
+ !/function\s+render\(/.test(line),
45
+ )
46
+ .map((line: string) => line.trim());
47
+ expect(unawaited).toEqual([]);
48
+ });
49
+ });
@@ -331,6 +331,32 @@ describe("statusLogInjector", () => {
331
331
  expect(html).toContain("updateCaptchaStatus");
332
332
  });
333
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
+
334
360
  it("fills the events slot when the layout provides one", () => {
335
361
  const html = handler(
336
362
  page(`<form></form>${slotMarkup("events")}`),