@nascentdigital/funnel-services 4.4.18
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/README.md +7 -0
- package/dist/analytics/Analytics.d.ts +11 -0
- package/dist/analytics/Analytics.js +48 -0
- package/dist/analytics/GoogleAnalytics.d.ts +16 -0
- package/dist/analytics/GoogleAnalytics.js +92 -0
- package/dist/analytics/index.d.ts +2 -0
- package/dist/analytics/index.js +18 -0
- package/dist/api/ApiClient.d.ts +18 -0
- package/dist/api/ApiClient.js +43 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +17 -0
- package/dist/captcha/MockHumanVerification.d.ts +4 -0
- package/dist/captcha/MockHumanVerification.js +11 -0
- package/dist/captcha/RecaptchaAdapter.d.ts +18 -0
- package/dist/captcha/RecaptchaAdapter.js +43 -0
- package/dist/captcha/errors/CaptchaError.d.ts +12 -0
- package/dist/captcha/errors/CaptchaError.js +19 -0
- package/dist/captcha/errors/CaptchaErrors.d.ts +8 -0
- package/dist/captcha/errors/CaptchaErrors.js +31 -0
- package/dist/captcha/errors/CaptchaVerificationError.d.ts +5 -0
- package/dist/captcha/errors/CaptchaVerificationError.js +11 -0
- package/dist/captcha/errors/index.d.ts +3 -0
- package/dist/captcha/errors/index.js +24 -0
- package/dist/captcha/index.d.ts +3 -0
- package/dist/captcha/index.js +19 -0
- package/dist/consent/ConsentActions.d.ts +5 -0
- package/dist/consent/ConsentActions.js +41 -0
- package/dist/consent/ConsentData.d.ts +13 -0
- package/dist/consent/ConsentData.js +35 -0
- package/dist/consent/CookieConsent.d.ts +19 -0
- package/dist/consent/CookieConsent.js +161 -0
- package/dist/consent/index.d.ts +2 -0
- package/dist/consent/index.js +18 -0
- package/dist/identity/actions.d.ts +4 -0
- package/dist/identity/actions.js +22 -0
- package/dist/identity/api/Identity.d.ts +11 -0
- package/dist/identity/api/Identity.js +2 -0
- package/dist/identity/api/IdentityService.d.ts +9 -0
- package/dist/identity/api/IdentityService.js +27 -0
- package/dist/identity/api/Profile.d.ts +10 -0
- package/dist/identity/api/Profile.js +2 -0
- package/dist/identity/api/ProfileService.d.ts +12 -0
- package/dist/identity/api/ProfileService.js +27 -0
- package/dist/identity/api/index.d.ts +4 -0
- package/dist/identity/api/index.js +20 -0
- package/dist/identity/auth0/Auth0IdentityService.d.ts +9 -0
- package/dist/identity/auth0/Auth0IdentityService.js +27 -0
- package/dist/identity/auth0/Auth0Profile.d.ts +30 -0
- package/dist/identity/auth0/Auth0Profile.js +57 -0
- package/dist/identity/auth0/Auth0ProfileService.d.ts +21 -0
- package/dist/identity/auth0/Auth0ProfileService.js +69 -0
- package/dist/identity/auth0/index.d.ts +2 -0
- package/dist/identity/auth0/index.js +18 -0
- package/dist/identity/client/ClientProfile.d.ts +27 -0
- package/dist/identity/client/ClientProfile.js +31 -0
- package/dist/identity/client/IdentityContainer.d.ts +12 -0
- package/dist/identity/client/IdentityContainer.js +23 -0
- package/dist/identity/client/IdentityContext.d.ts +8 -0
- package/dist/identity/client/IdentityContext.js +6 -0
- package/dist/identity/client/index.d.ts +3 -0
- package/dist/identity/client/index.js +19 -0
- package/dist/identity/client/useIdentity.d.ts +2 -0
- package/dist/identity/client/useIdentity.js +9 -0
- package/dist/identity/client/useProfile.d.ts +2 -0
- package/dist/identity/client/useProfile.js +9 -0
- package/dist/identity/index.d.ts +3 -0
- package/dist/identity/index.js +19 -0
- package/dist/identity/server/IdentityProvider.d.ts +5 -0
- package/dist/identity/server/IdentityProvider.js +29 -0
- package/dist/identity/server/index.d.ts +1 -0
- package/dist/identity/server/index.js +17 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/ip/index.d.ts +1 -0
- package/dist/ip/index.js +17 -0
- package/dist/ip/useIpAddress.d.ts +1 -0
- package/dist/ip/useIpAddress.js +69 -0
- package/dist/leadgen/AbstractPipeDriveAdapter.d.ts +27 -0
- package/dist/leadgen/AbstractPipeDriveAdapter.js +43 -0
- package/dist/leadgen/ConfigPipeDriveAdapter.d.ts +18 -0
- package/dist/leadgen/ConfigPipeDriveAdapter.js +60 -0
- package/dist/leadgen/MockPipedrive.d.ts +16 -0
- package/dist/leadgen/MockPipedrive.js +32 -0
- package/dist/leadgen/PipedriveClient.d.ts +40 -0
- package/dist/leadgen/PipedriveClient.js +223 -0
- package/dist/leadgen/index.d.ts +4 -0
- package/dist/leadgen/index.js +20 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +20 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Services
|
|
2
|
+
|
|
3
|
+
## API Testing
|
|
4
|
+
|
|
5
|
+
We use [Bruno](https://www.usebruno.com/) to share api collection to test and use. This allows us to share test endpoints and collaborate through git.
|
|
6
|
+
|
|
7
|
+
**Be Careful: Do not commit secret values through bruno configs! use [environment variables](https://docs.usebruno.com/get-started/variables/environment-variables) to mange secret variables, which bruno stores locally**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CookieConsent } from '../consent';
|
|
2
|
+
export declare namespace Analytics {
|
|
3
|
+
interface Provider {
|
|
4
|
+
trackPageView(): void;
|
|
5
|
+
trackEvent(): void;
|
|
6
|
+
onConsentChange(state: CookieConsent.State): void;
|
|
7
|
+
}
|
|
8
|
+
function bindProvider(provider: Provider): void;
|
|
9
|
+
function trackPageView(): void;
|
|
10
|
+
function trackEvent(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.Analytics = void 0;
|
|
5
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
6
|
+
const consent_1 = require("../consent");
|
|
7
|
+
// namespace
|
|
8
|
+
var Analytics;
|
|
9
|
+
(function (Analytics) {
|
|
10
|
+
// helper
|
|
11
|
+
const getProvider = () => {
|
|
12
|
+
// throw if provider isn't initialized
|
|
13
|
+
const provider = _provider;
|
|
14
|
+
if (!provider) {
|
|
15
|
+
throw new funnel_core_1.InvalidOperationError('Attempt to access provider before being bound');
|
|
16
|
+
}
|
|
17
|
+
// return provider
|
|
18
|
+
return provider;
|
|
19
|
+
};
|
|
20
|
+
// methods
|
|
21
|
+
function bindProvider(provider) {
|
|
22
|
+
// skip if provider is the same
|
|
23
|
+
if (provider === _provider) {
|
|
24
|
+
console.warn('[Analytics] ignoring duplicate provider binding');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// throw if there's already a provider
|
|
28
|
+
if (_provider) {
|
|
29
|
+
throw new funnel_core_1.InvalidOperationError('Provider is already bound');
|
|
30
|
+
}
|
|
31
|
+
// bind provider
|
|
32
|
+
_provider = provider;
|
|
33
|
+
// forward consent changes
|
|
34
|
+
consent_1.CookieConsent.state$()
|
|
35
|
+
.subscribe(state => provider.onConsentChange(state));
|
|
36
|
+
}
|
|
37
|
+
Analytics.bindProvider = bindProvider;
|
|
38
|
+
function trackPageView() {
|
|
39
|
+
return getProvider().trackPageView();
|
|
40
|
+
}
|
|
41
|
+
Analytics.trackPageView = trackPageView;
|
|
42
|
+
function trackEvent() {
|
|
43
|
+
return getProvider().trackEvent();
|
|
44
|
+
}
|
|
45
|
+
Analytics.trackEvent = trackEvent;
|
|
46
|
+
})(Analytics || (exports.Analytics = Analytics = {}));
|
|
47
|
+
// provider
|
|
48
|
+
let _provider = undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ConsentService } from '@nascentdigital/funnel-core';
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
dataLayer?: any[];
|
|
5
|
+
}
|
|
6
|
+
function gtag(...value: any[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function GoogleAnalytics({ tagId, enableAds, debugMode }: GoogleAnalytics.Props): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare namespace GoogleAnalytics {
|
|
10
|
+
type Props = {
|
|
11
|
+
tagId: string;
|
|
12
|
+
enableAds?: boolean;
|
|
13
|
+
debugMode?: boolean;
|
|
14
|
+
};
|
|
15
|
+
const services: ReadonlyArray<ConsentService>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GoogleAnalytics = GoogleAnalytics;
|
|
8
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
9
|
+
const script_1 = __importDefault(require("next/script"));
|
|
10
|
+
const react_1 = require("react");
|
|
11
|
+
const Analytics_1 = require("./Analytics");
|
|
12
|
+
// component
|
|
13
|
+
function GoogleAnalytics({ tagId, enableAds = false, debugMode = false }) {
|
|
14
|
+
// bind props + provider
|
|
15
|
+
const [consent, setConsent] = (0, react_1.useState)();
|
|
16
|
+
const provider = (0, react_1.useMemo)(() => new GoogleAnalyticsProvider(tagId, setConsent), [tagId]);
|
|
17
|
+
const allowed = (0, react_1.useMemo)(() => !!consent
|
|
18
|
+
&& consent.services.some(c => c.service === 'analytics_storage' && c.accepted), [consent]);
|
|
19
|
+
// mount
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
// bind provider
|
|
22
|
+
Analytics_1.Analytics.bindProvider(provider);
|
|
23
|
+
}, [provider]);
|
|
24
|
+
// update consent when changed
|
|
25
|
+
(0, react_1.useEffect)(() => {
|
|
26
|
+
// skip if consent isn't set
|
|
27
|
+
if (!consent) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// fail if datalayer isn't bound
|
|
31
|
+
else if (!window.dataLayer) {
|
|
32
|
+
console.warn('[GoogleAnalytics] attempt to update consent before dataLayer is bound');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// bind defaults (deny all by default)
|
|
36
|
+
gtag('consent', 'update', consent.services.reduce((consent, { category, service, accepted }) => {
|
|
37
|
+
// set consent for service
|
|
38
|
+
consent[service] = accepted && (enableAds || category !== 'advertisement')
|
|
39
|
+
? 'granted'
|
|
40
|
+
: 'denied';
|
|
41
|
+
// keep reducing
|
|
42
|
+
return consent;
|
|
43
|
+
}, {}));
|
|
44
|
+
}, [consent, enableAds]);
|
|
45
|
+
// render
|
|
46
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(script_1.default, { id: "_funnel-analytics-ga-init", dangerouslySetInnerHTML: {
|
|
47
|
+
__html: `
|
|
48
|
+
window.dataLayer = window.dataLayer || [];
|
|
49
|
+
function gtag(){dataLayer.push(arguments);}
|
|
50
|
+
gtag('consent', 'default', {
|
|
51
|
+
'ad_user_data': 'denied',
|
|
52
|
+
'ad_personalization': 'denied',
|
|
53
|
+
'ad_storage': 'denied',
|
|
54
|
+
'analytics_storage': 'denied',
|
|
55
|
+
'security_storage': 'denied',
|
|
56
|
+
'personalization_storage': 'denied',
|
|
57
|
+
'functionality_storage': 'denied',
|
|
58
|
+
'wait_for_update': 500
|
|
59
|
+
});
|
|
60
|
+
gtag('js', new Date());
|
|
61
|
+
gtag('config', '${tagId}' ${debugMode ? ",{ 'debug_mode': true }" : ''});`,
|
|
62
|
+
} }, "_funnel-analytics-ga-init"), allowed &&
|
|
63
|
+
(0, jsx_runtime_1.jsx)(script_1.default, { id: "_funnel-analytics-ga", src: `https://www.googletagmanager.com/gtag/js?id=${tagId}` }, "_funnel-analytics-ga")] }));
|
|
64
|
+
}
|
|
65
|
+
// extension
|
|
66
|
+
(function (GoogleAnalytics) {
|
|
67
|
+
// constants
|
|
68
|
+
GoogleAnalytics.services = [
|
|
69
|
+
'functionality_storage', 'personalization_storage',
|
|
70
|
+
'security_storage',
|
|
71
|
+
'analytics_storage',
|
|
72
|
+
'ad_storage', 'ad_user_data', 'ad_personalization'
|
|
73
|
+
];
|
|
74
|
+
})(GoogleAnalytics || (exports.GoogleAnalytics = GoogleAnalytics = {}));
|
|
75
|
+
// provider
|
|
76
|
+
class GoogleAnalyticsProvider {
|
|
77
|
+
constructor(tagId, setConsent) {
|
|
78
|
+
this.tagId = tagId;
|
|
79
|
+
this.setConsent = setConsent;
|
|
80
|
+
}
|
|
81
|
+
trackPageView() {
|
|
82
|
+
throw new Error('Method not implemented.');
|
|
83
|
+
}
|
|
84
|
+
trackEvent() {
|
|
85
|
+
throw new Error('Method not implemented.');
|
|
86
|
+
}
|
|
87
|
+
onConsentChange(consent) {
|
|
88
|
+
console.debug('[GoogleAnalyticsProvider] handling consent change', consent);
|
|
89
|
+
// forward consent
|
|
90
|
+
this.setConsent(consent);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./Analytics"), exports);
|
|
18
|
+
__exportStar(require("./GoogleAnalytics"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
export declare class ApiClient {
|
|
3
|
+
private readonly _apiUrl?;
|
|
4
|
+
private readonly _apiToken?;
|
|
5
|
+
constructor();
|
|
6
|
+
get<TResponse = any>(args: Omit<ApiClient.SendArgs, 'method'>): Promise<TResponse>;
|
|
7
|
+
post<TResponse = any>(args: Omit<ApiClient.SendArgs, 'method'>): Promise<TResponse>;
|
|
8
|
+
send<TResponse>({ method, path, headers, body }: ApiClient.SendArgs): Promise<TResponse>;
|
|
9
|
+
}
|
|
10
|
+
export declare namespace ApiClient {
|
|
11
|
+
type SendArgs = {
|
|
12
|
+
method: 'GET' | 'POST';
|
|
13
|
+
path: string;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
body?: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare const apiClient: ApiClient;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.apiClient = exports.ApiClient = void 0;
|
|
4
|
+
require("server-only");
|
|
5
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
6
|
+
// class
|
|
7
|
+
class ApiClient {
|
|
8
|
+
constructor() {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
// initialize instance variables
|
|
11
|
+
this._apiUrl = (_a = process.env.API_URL) !== null && _a !== void 0 ? _a : undefined;
|
|
12
|
+
this._apiToken = (_b = process.env.API_TOKEN) !== null && _b !== void 0 ? _b : undefined;
|
|
13
|
+
}
|
|
14
|
+
get(args) {
|
|
15
|
+
return this.send(Object.assign(Object.assign({}, args), { method: 'GET' }));
|
|
16
|
+
}
|
|
17
|
+
post(args) {
|
|
18
|
+
return this.send(Object.assign(Object.assign({}, args), { method: 'POST' }));
|
|
19
|
+
}
|
|
20
|
+
async send({ method, path, headers = {}, body }) {
|
|
21
|
+
// fail if api url/token are missing
|
|
22
|
+
const { _apiUrl, _apiToken } = this;
|
|
23
|
+
if (!_apiUrl || !_apiToken) {
|
|
24
|
+
throw new funnel_core_1.IllegalStateError('ApiClient is missing API_URL/API_TOKEN configuration');
|
|
25
|
+
}
|
|
26
|
+
// send request
|
|
27
|
+
const url = new URL(path, _apiUrl);
|
|
28
|
+
const response = await fetch(url.href, {
|
|
29
|
+
method,
|
|
30
|
+
headers: Object.assign(Object.assign({}, headers), { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${_apiToken}` }),
|
|
31
|
+
body
|
|
32
|
+
});
|
|
33
|
+
// throw if there's an error
|
|
34
|
+
await funnel_core_1.IsometricErrorUtils.checkResponse(response, error => {
|
|
35
|
+
console.error('[ApiClient] request failed', error);
|
|
36
|
+
});
|
|
37
|
+
// or return response
|
|
38
|
+
return response.json();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.ApiClient = ApiClient;
|
|
42
|
+
// exports
|
|
43
|
+
exports.apiClient = new ApiClient();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ApiClient';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./ApiClient"), exports);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MockHumanVerification = void 0;
|
|
4
|
+
// class
|
|
5
|
+
class MockHumanVerification {
|
|
6
|
+
verify(args) {
|
|
7
|
+
console.debug('[MockHumanVerification] verifying user is human');
|
|
8
|
+
return Promise.resolve(undefined);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.MockHumanVerification = MockHumanVerification;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IHumanVerification } from '@nascentdigital/funnel-core';
|
|
2
|
+
export declare class RecaptchaAdapter implements IHumanVerification {
|
|
3
|
+
private readonly _recaptchaSecretKey;
|
|
4
|
+
constructor({ recaptchaSecretKey }: RecaptchaAdapter.ConstructorArgs);
|
|
5
|
+
verify(args: IHumanVerification.VerifyUserIsHumanArgs): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare namespace RecaptchaAdapter {
|
|
8
|
+
type RecaptchaResponse = {
|
|
9
|
+
success: boolean;
|
|
10
|
+
challenge_ts: unknown;
|
|
11
|
+
host: string;
|
|
12
|
+
'error-codes'?: Array<string>;
|
|
13
|
+
};
|
|
14
|
+
type ConstructorArgs = {
|
|
15
|
+
recaptchaSecretKey: string;
|
|
16
|
+
};
|
|
17
|
+
function getVerificationToken(): Promise<string>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecaptchaAdapter = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
// class
|
|
6
|
+
class RecaptchaAdapter {
|
|
7
|
+
constructor({ recaptchaSecretKey }) {
|
|
8
|
+
// initialize instance variables
|
|
9
|
+
this._recaptchaSecretKey = recaptchaSecretKey;
|
|
10
|
+
}
|
|
11
|
+
async verify(args) {
|
|
12
|
+
var _a;
|
|
13
|
+
console.debug('[RecaptchaAdapter] verifying user is human');
|
|
14
|
+
// create verification URL
|
|
15
|
+
const verificationUrl = new URL('https://www.google.com/recaptcha/api/siteverify');
|
|
16
|
+
verificationUrl.searchParams.set('secret', this._recaptchaSecretKey);
|
|
17
|
+
verificationUrl.searchParams.set('response', args.verificationToken);
|
|
18
|
+
// get score from Google
|
|
19
|
+
const verifiedResponse = await fetch(verificationUrl.href, { method: 'POST' });
|
|
20
|
+
const response = await verifiedResponse.json();
|
|
21
|
+
// throw if there's an error
|
|
22
|
+
if (!response.success) {
|
|
23
|
+
const [code] = (_a = response['error-codes']) !== null && _a !== void 0 ? _a : [];
|
|
24
|
+
throw new errors_1.CaptchaVerificationError('User could not be verified', code);
|
|
25
|
+
}
|
|
26
|
+
console.debug('[RecaptchaAdapter] user is human');
|
|
27
|
+
return Promise.resolve(undefined);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.RecaptchaAdapter = RecaptchaAdapter;
|
|
31
|
+
// extension
|
|
32
|
+
(function (RecaptchaAdapter) {
|
|
33
|
+
// helpers
|
|
34
|
+
function getVerificationToken() {
|
|
35
|
+
return new Promise((resolve) => {
|
|
36
|
+
grecaptcha.ready(function () {
|
|
37
|
+
grecaptcha.execute(process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY || '', { action: 'submit' })
|
|
38
|
+
.then(resolve);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
RecaptchaAdapter.getVerificationToken = getVerificationToken;
|
|
43
|
+
})(RecaptchaAdapter || (exports.RecaptchaAdapter = RecaptchaAdapter = {}));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IsometricError, SerializedIsometricError } from '@nascentdigital/funnel-core';
|
|
2
|
+
export declare class CaptchaError extends IsometricError {
|
|
3
|
+
readonly code?: string;
|
|
4
|
+
constructor(args: CaptchaError.ConstructorArgs);
|
|
5
|
+
serialize(): SerializedIsometricError;
|
|
6
|
+
}
|
|
7
|
+
export declare namespace CaptchaError {
|
|
8
|
+
type ConstructorArgs = IsometricError.ConstructorArgs.WithoutModuleId & {
|
|
9
|
+
code?: string;
|
|
10
|
+
};
|
|
11
|
+
type Options = Omit<ConstructorArgs, 'message'>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CaptchaError = void 0;
|
|
4
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
5
|
+
const CaptchaErrors_1 = require("./CaptchaErrors");
|
|
6
|
+
// error
|
|
7
|
+
class CaptchaError extends funnel_core_1.IsometricError {
|
|
8
|
+
constructor(args) {
|
|
9
|
+
// construct base
|
|
10
|
+
super(Object.assign(Object.assign({}, args), { moduleId: CaptchaErrors_1.CaptchaErrors.moduleId }));
|
|
11
|
+
// initialize instance variables
|
|
12
|
+
this.code = args.code;
|
|
13
|
+
}
|
|
14
|
+
serialize() {
|
|
15
|
+
const { code = null } = this;
|
|
16
|
+
return Object.assign(Object.assign({}, super.serialize()), { code });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.CaptchaError = CaptchaError;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IsometricError, IsometricErrorModule, SerializedIsometricError } from '@nascentdigital/funnel-core';
|
|
2
|
+
export declare class CaptchaErrors implements IsometricErrorModule {
|
|
3
|
+
readonly id: IsometricErrorModule.Id;
|
|
4
|
+
deserialize(data: SerializedIsometricError): IsometricError | undefined;
|
|
5
|
+
}
|
|
6
|
+
export declare namespace CaptchaErrors {
|
|
7
|
+
const moduleId: IsometricErrorModule.Id;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CaptchaErrors = void 0;
|
|
4
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
5
|
+
const CaptchaVerificationError_1 = require("./CaptchaVerificationError");
|
|
6
|
+
// module
|
|
7
|
+
class CaptchaErrors {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.id = CaptchaErrors.moduleId;
|
|
10
|
+
}
|
|
11
|
+
deserialize(data) {
|
|
12
|
+
// skip if module doesn't match
|
|
13
|
+
if (data.moduleId !== this.id) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
// convert
|
|
17
|
+
switch (data.name) {
|
|
18
|
+
// re-hydrate error
|
|
19
|
+
case CaptchaVerificationError_1.CaptchaVerificationError.name:
|
|
20
|
+
return new CaptchaVerificationError_1.CaptchaVerificationError(data.message, funnel_core_1.Value.parseString(data.code));
|
|
21
|
+
// or ignore if not matching
|
|
22
|
+
default:
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.CaptchaErrors = CaptchaErrors;
|
|
28
|
+
// extensions
|
|
29
|
+
(function (CaptchaErrors) {
|
|
30
|
+
CaptchaErrors.moduleId = 'captcha';
|
|
31
|
+
})(CaptchaErrors || (exports.CaptchaErrors = CaptchaErrors = {}));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CaptchaVerificationError = void 0;
|
|
4
|
+
const CaptchaError_1 = require("./CaptchaError");
|
|
5
|
+
// class
|
|
6
|
+
class CaptchaVerificationError extends CaptchaError_1.CaptchaError {
|
|
7
|
+
constructor(message = 'Captcha verification failed', code, options = {}) {
|
|
8
|
+
super(Object.assign({ message, code }, options));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.CaptchaVerificationError = CaptchaVerificationError;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
18
|
+
const CaptchaErrors_1 = require("./CaptchaErrors");
|
|
19
|
+
// exports
|
|
20
|
+
__exportStar(require("./CaptchaError"), exports);
|
|
21
|
+
__exportStar(require("./CaptchaErrors"), exports);
|
|
22
|
+
__exportStar(require("./CaptchaVerificationError"), exports);
|
|
23
|
+
// bind module
|
|
24
|
+
funnel_core_1.IsometricErrorUtils.registerModule(CaptchaErrors_1.CaptchaErrors);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./errors"), exports);
|
|
18
|
+
__exportStar(require("./MockHumanVerification"), exports);
|
|
19
|
+
__exportStar(require("./RecaptchaAdapter"), exports);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.ConsentActions = void 0;
|
|
15
|
+
require("server-only");
|
|
16
|
+
const headers_1 = require("next/headers");
|
|
17
|
+
const api_1 = require("../api");
|
|
18
|
+
// handler
|
|
19
|
+
var ConsentActions;
|
|
20
|
+
(function (ConsentActions) {
|
|
21
|
+
async function captureConsent(data) {
|
|
22
|
+
var _a;
|
|
23
|
+
// create dto
|
|
24
|
+
const { ip, url, userId } = data, consent = __rest(data, ["ip", "url", "userId"]);
|
|
25
|
+
const requestHeaders = await (0, headers_1.headers)();
|
|
26
|
+
const dto = {
|
|
27
|
+
userId,
|
|
28
|
+
userAgent: (_a = requestHeaders.get('user-agent')) !== null && _a !== void 0 ? _a : 'Unknown',
|
|
29
|
+
ip,
|
|
30
|
+
url,
|
|
31
|
+
consent
|
|
32
|
+
};
|
|
33
|
+
console.debug('[ConsentActions] submitting', dto);
|
|
34
|
+
// submit to funnel-api
|
|
35
|
+
await api_1.apiClient.post({
|
|
36
|
+
path: '/api/consent',
|
|
37
|
+
body: JSON.stringify(dto)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
ConsentActions.captureConsent = captureConsent;
|
|
41
|
+
})(ConsentActions || (exports.ConsentActions = ConsentActions = {}));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ConsentCategory, ConsentService } from '@nascentdigital/funnel-core';
|
|
2
|
+
import * as Consent from 'vanilla-cookieconsent';
|
|
3
|
+
export type ConsentData = {
|
|
4
|
+
ip?: string;
|
|
5
|
+
url: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
choice: Consent.AcceptType;
|
|
8
|
+
categories: ReadonlyArray<ConsentCategory.Choice>;
|
|
9
|
+
services: ReadonlyArray<ConsentService.Choice>;
|
|
10
|
+
};
|
|
11
|
+
export declare namespace ConsentData {
|
|
12
|
+
function parse(value: any): ConsentData;
|
|
13
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsentData = void 0;
|
|
4
|
+
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
5
|
+
// extension
|
|
6
|
+
var ConsentData;
|
|
7
|
+
(function (ConsentData) {
|
|
8
|
+
function parse(value) {
|
|
9
|
+
// throw if not an object
|
|
10
|
+
if (!value || typeof value !== 'object') {
|
|
11
|
+
throw new funnel_core_1.ArgumentError('ConsentData must be a valid object');
|
|
12
|
+
}
|
|
13
|
+
// throw if props are missing
|
|
14
|
+
else if (!('ip' in value) || typeof value.ip !== 'string' ||
|
|
15
|
+
!('url' in value) || typeof value.url !== 'string' ||
|
|
16
|
+
!('userId' in value) || typeof value.userId !== 'string' ||
|
|
17
|
+
!('choice' in value) || typeof value.choice !== 'string' ||
|
|
18
|
+
!('categories' in value) || !Array.isArray(value.categories) ||
|
|
19
|
+
!value.categories.every(funnel_core_1.ConsentCategory.Choice.filter) ||
|
|
20
|
+
!('services' in value) || !Array.isArray(value.services) ||
|
|
21
|
+
!value.services.every((v) => typeof v !== 'string')) {
|
|
22
|
+
throw new funnel_core_1.ArgumentError('ConsentData has invalid format');
|
|
23
|
+
}
|
|
24
|
+
// destructure
|
|
25
|
+
return {
|
|
26
|
+
ip: value.ip,
|
|
27
|
+
url: value.url,
|
|
28
|
+
userId: value.userId,
|
|
29
|
+
choice: value.choice,
|
|
30
|
+
categories: value.categories,
|
|
31
|
+
services: value.services
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
ConsentData.parse = parse;
|
|
35
|
+
})(ConsentData || (exports.ConsentData = ConsentData = {}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ConsentCategory, ConsentService, Transform } from '@nascentdigital/funnel-core';
|
|
2
|
+
import { Jsonify } from 'type-fest';
|
|
3
|
+
import * as Consent from 'vanilla-cookieconsent';
|
|
4
|
+
import { ConsentData } from './ConsentData';
|
|
5
|
+
export declare function CookieConsent({ consentAction, copy }: CookieConsent.Props): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare namespace CookieConsent {
|
|
7
|
+
type Props = {
|
|
8
|
+
consentAction: Transform.Async<ConsentData, void>;
|
|
9
|
+
copy: Copy;
|
|
10
|
+
};
|
|
11
|
+
type State = {
|
|
12
|
+
categories: ReadonlyArray<ConsentCategory.Choice>;
|
|
13
|
+
services: ReadonlyArray<ConsentService.Choice>;
|
|
14
|
+
};
|
|
15
|
+
type Copy = Jsonify<Consent.Translation> & {
|
|
16
|
+
cta: string;
|
|
17
|
+
};
|
|
18
|
+
function state$(): import("rxjs").Observable<State>;
|
|
19
|
+
}
|