Skip to content

Commit

Permalink
Merge branch 'main' into chore/owners
Browse files Browse the repository at this point in the history
  • Loading branch information
faris-imi authored Feb 22, 2024
2 parents b8f4fca + 19238d8 commit eb492e3
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 23 deletions.
97 changes: 81 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This is a JavaScript library to easily configure the loading of the [hCaptcha](h
1. [Installation](#installation)
2. [Implementation](#implementation)
3. [Props](#props)
3. [Legacy Support](#legacy-support)

### Installation
```
Expand All @@ -30,19 +31,83 @@ const { response } = await hcaptcha.execute({ async: true });
```

### Props
| Name | Values/Type | Required | Default | Description |
|-------------------|-------------|----------|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `loadAsync` | Boolean | No | `true` | Set if the script should be loaded asynchronously. |
| `cleanup` | Boolean | No | `true` | Remove script tag after setup. |
| `crossOrigin` | String | No | `-` | Set script cross origin attribute such as "anonymous". |
| `scriptLocation` | HTMLElement | No | `document.head` | Location of where to append the script tag. Make sure to add it to an area that will persist to prevent loading multiple times in the same document view. |
| `apihost` | String | No | `-` | See enterprise docs. |
| `assethost` | String | No | `-` | See enterprise docs. |
| `endpoint` | String | No | `-` | See enterprise docs. |
| `hl` | String | No | `-` | See enterprise docs. |
| `host` | String | No | `-` | See enterprise docs. |
| `imghost` | String | No | `-` | See enterprise docs. |
| `recaptchacompat` | String | No | `-` | See enterprise docs. |
| `reportapi` | String | No | `-` | See enterprise docs. |
| `sentry` | Boolean | No | `-` | See enterprise docs. |
| `custom` | Boolean | No | `-` | See enterprise docs. |
| Name | Values/Type | Required | Default | Description |
|-------------------|-------------|----------|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `loadAsync` | Boolean | No | `true` | Set if the script should be loaded asynchronously. |
| `cleanup` | Boolean | No | `true` | Remove script tag after setup. |
| `crossOrigin` | String | No | `-` | Set script cross origin attribute such as "anonymous". |
| `scriptSource` | String | No | `https://js.hcaptcha.com/1/api.js` | Set script source URI. Takes precedence over `secureApi`. |
| `scriptLocation` | HTMLElement | No | `document.head` | Location of where to append the script tag. Make sure to add it to an area that will persist to prevent loading multiple times in the same document view. |
| `secureApi` | Boolean | No | `false` | See enterprise docs. |
| `apihost` | String | No | `-` | See enterprise docs. |
| `assethost` | String | No | `-` | See enterprise docs. |
| `endpoint` | String | No | `-` | See enterprise docs. |
| `hl` | String | No | `-` | See enterprise docs. |
| `host` | String | No | `-` | See enterprise docs. |
| `imghost` | String | No | `-` | See enterprise docs. |
| `recaptchacompat` | String | No | `-` | See enterprise docs. |
| `reportapi` | String | No | `-` | See enterprise docs. |
| `sentry` | Boolean | No | `-` | See enterprise docs. |
| `custom` | Boolean | No | `-` | See enterprise docs. |



## Legacy Support
In order to support older browsers, a separate bundle is generated in which all ES6 code is compiled down to ES5 along with an optional polyfill bundle.

- `polyfills.js`: Provides polyfills for features not supported in older browsers.
- `index.es5.js`: **@hcaptcha/loader** package compiled for ES5 environments.

### Import Bundle(s)
Both bundles generated use IIFE format rather than a more modern import syntax such as `require` or `esm`.

```js
// Optional polyfill import
import '@hCaptcha/loader/dist/polyfills.js';
// ES5 version of hCaptcha Loader
import '@hCaptcha/loader/dist/index.es5.js';

hCaptchaLoader().then(function(hcaptcha) {
var element = document.createElement('div');
// hCaptcha API is ready
hcaptcha.render(element, {
sitekey: 'YOUR_SITE_KEY',
// Additional options here
});
});

```
### TypeScript
To handle typescript with ES5 version, use the following statement.
```ts
declare global {
interface Window {
hCaptchaLoader: any;
}
}
```

### CDN
The hCaptcha Loader targeted for older browsers can also be imported via CDN by using [UNPKG](https://www.unpkg.com/), see example below.


```html
<!DOCTYPE html>
<head>
<script type="text/javascript" src="https://unpkg.com/@hcaptcha/loader@latest/dist/polyfills.js"></script>
<script type="text/javascript" src="https://unpkg.com/@hcaptcha/loader@latest/dist/index.es5.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
hCaptchaLoader().then(function(hcaptcha) {
// hCaptcha API is ready
hcaptcha.render('container', {
sitekey: 'YOUR_SITE_KEY',
// Additional options here
});
});
</script>
</body>
</html>
```
16 changes: 16 additions & 0 deletions lib/__test__/script.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@ describe('fetchScript', () => {
const [script] = nodes;
expect(script.src).toMatch(`${apihost}/1/api.js?onload=${HCAPTCHA_LOAD_FN_NAME}`);
});

it('should change hCaptcha JS API if secureApi is specified', async () => {
const secureApi = true;
await fetchScript({ secureApi });

const [script] = nodes;
expect(script.src).toMatch(`https://js.hcaptcha.com/1/secure-api.js?onload=${HCAPTCHA_LOAD_FN_NAME}`);
});

it('should change hCaptcha JS API if scriptSource is specified', async () => {
const scriptSource = 'hcaptcha.com/1/api.js';
await fetchScript({ scriptSource });

const [script] = nodes;
expect(script.src).toMatch(`${scriptSource}?onload=${HCAPTCHA_LOAD_FN_NAME}`);
});
});

describe('cleanup', () => {
Expand Down
52 changes: 51 additions & 1 deletion lib/esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fileURLToPath } from 'url';

import { build, context, analyzeMetafile } from 'esbuild';
import * as dotenv from 'dotenv';
import swc from '@swc/core';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Expand Down Expand Up @@ -44,6 +45,14 @@ const config = {
sourcemap: BUILD === 'development',
};

const swcOptions = {
minify: true,
sourceMaps: BUILD === 'development',
jsc: {
target: 'es5',
},
};


if (WATCH) {
const ctx = await context({
Expand All @@ -57,6 +66,7 @@ if (WATCH) {
});
await ctx.watch();
} else {
// Transpile TypeScript to ESM
const resultESM = await build({
...config,
format: 'esm',
Expand All @@ -67,11 +77,46 @@ if (WATCH) {
]
});

// Transpile TypeScript to CommonJS
const resultCJS = await build({
...config,
format: 'cjs',
outfile: resolve(DIST, 'index.cjs'),
treeShaking: true
treeShaking: true,
});

// Transform to ES5
const transformedESM = await swc.transformFile(resolve(DIST, 'index.mjs'), swcOptions);

// Build ES5 bundle
const resultES5 = await build({
...config,
entryPoints: undefined,
globalName: 'hCaptchaLoaderPkg',
stdin: {
contents: transformedESM.code,
resolveDir: DIST,
sourcefile: 'index.es5.js',
},
outfile: resolve(DIST, 'index.es5.js'),
footer: {
js: 'window.hCaptchaLoader = hCaptchaLoaderPkg.hCaptchaLoader;',
},
treeShaking: true,
target: [
'es5',
]
});

// Add Polyfills
await build({
...config,
entryPoints: [resolve(SRC, 'polyfills.ts')],
outfile: resolve(DIST, 'polyfills.js'),
treeShaking: true,
target: [
'es5',
]
});

if (DEBUG) {
Expand All @@ -81,7 +126,12 @@ if (WATCH) {
const analyzeCJS = await analyzeMetafile(resultCJS.metafile, {
verbose: false
});
const analyzeES5 = await analyzeMetafile(resultES5.metafile, {
verbose: false
});

console.log(analyzeESM);
console.log(analyzeCJS);
console.log(analyzeES5);
}
}
3 changes: 2 additions & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"test:unit": "jest"
},
"dependencies": {
"@sentry/browser": "^7.73.0"
"@sentry/browser": "^7.73.0",
"core-js": "^3.35.1"
},
"devDependencies": {
"@hcaptcha/types": "^1.0.3",
Expand Down
2 changes: 1 addition & 1 deletion lib/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@ export async function loadScript(params, retries = 0) {
}


export async function hCaptchaLoader(params) {
export async function hCaptchaLoader(params = {}) {
return await loadScript(params);
}
4 changes: 4 additions & 0 deletions lib/src/polyfills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import 'core-js/es/array/find';
import 'core-js/es/object/assign';
import 'core-js/es/object/entries';
import 'core-js/es/object/get-own-property-descriptors';
16 changes: 13 additions & 3 deletions lib/src/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export function fetchScript({
loadAsync = true,
crossOrigin,
apihost = 'https://js.hcaptcha.com',
cleanup = true
cleanup = true,
secureApi = false,
scriptSource = ''
}: IScriptParams = {}) {
const element = getMountElement(scriptLocation);
const frame: any = getFrame(element);
Expand All @@ -18,13 +20,21 @@ export function fetchScript({
const script = frame.document.createElement('script');

script.id = SCRIPT_ID;
script.src = `${apihost}/1/api.js?onload=${HCAPTCHA_LOAD_FN_NAME}`;
if (scriptSource) {
script.src = `${scriptSource}?onload=${HCAPTCHA_LOAD_FN_NAME}`;
} else {
if (secureApi) {
script.src = `${apihost}/1/secure-api.js?onload=${HCAPTCHA_LOAD_FN_NAME}`;
} else {
script.src = `${apihost}/1/api.js?onload=${HCAPTCHA_LOAD_FN_NAME}`;
}
}
script.crossOrigin = crossOrigin;
script.async = loadAsync;

const onComplete = (event, callback) => {
try {
if (cleanup) {
if (!secureApi && cleanup) {
element.removeChild(script);
}
callback(event);
Expand Down
2 changes: 2 additions & 0 deletions lib/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export interface IScriptParams {
scriptLocation?: HTMLElement;
secureApi?: boolean;
scriptSource?: string;
apihost?: string;
loadAsync?: boolean;
cleanup?: boolean;
Expand Down
3 changes: 3 additions & 0 deletions lib/tsconfig.types.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@

"include": [
"src/**/*"
],
"exclude": [
"src/polyfills.ts"
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@hcaptcha/loader",
"description": "This is a JavaScript library to easily configure the loading of the hCaptcha JS client SDK with built-in error handling.",
"version": "1.1.3",
"version": "1.2.2",
"author": "hCaptcha team and contributors",
"license": "MIT",
"keywords": [
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit eb492e3

Please sign in to comment.