@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.
Files changed (90) hide show
  1. package/README.md +7 -0
  2. package/dist/analytics/Analytics.d.ts +11 -0
  3. package/dist/analytics/Analytics.js +48 -0
  4. package/dist/analytics/GoogleAnalytics.d.ts +16 -0
  5. package/dist/analytics/GoogleAnalytics.js +92 -0
  6. package/dist/analytics/index.d.ts +2 -0
  7. package/dist/analytics/index.js +18 -0
  8. package/dist/api/ApiClient.d.ts +18 -0
  9. package/dist/api/ApiClient.js +43 -0
  10. package/dist/api/index.d.ts +1 -0
  11. package/dist/api/index.js +17 -0
  12. package/dist/captcha/MockHumanVerification.d.ts +4 -0
  13. package/dist/captcha/MockHumanVerification.js +11 -0
  14. package/dist/captcha/RecaptchaAdapter.d.ts +18 -0
  15. package/dist/captcha/RecaptchaAdapter.js +43 -0
  16. package/dist/captcha/errors/CaptchaError.d.ts +12 -0
  17. package/dist/captcha/errors/CaptchaError.js +19 -0
  18. package/dist/captcha/errors/CaptchaErrors.d.ts +8 -0
  19. package/dist/captcha/errors/CaptchaErrors.js +31 -0
  20. package/dist/captcha/errors/CaptchaVerificationError.d.ts +5 -0
  21. package/dist/captcha/errors/CaptchaVerificationError.js +11 -0
  22. package/dist/captcha/errors/index.d.ts +3 -0
  23. package/dist/captcha/errors/index.js +24 -0
  24. package/dist/captcha/index.d.ts +3 -0
  25. package/dist/captcha/index.js +19 -0
  26. package/dist/consent/ConsentActions.d.ts +5 -0
  27. package/dist/consent/ConsentActions.js +41 -0
  28. package/dist/consent/ConsentData.d.ts +13 -0
  29. package/dist/consent/ConsentData.js +35 -0
  30. package/dist/consent/CookieConsent.d.ts +19 -0
  31. package/dist/consent/CookieConsent.js +161 -0
  32. package/dist/consent/index.d.ts +2 -0
  33. package/dist/consent/index.js +18 -0
  34. package/dist/identity/actions.d.ts +4 -0
  35. package/dist/identity/actions.js +22 -0
  36. package/dist/identity/api/Identity.d.ts +11 -0
  37. package/dist/identity/api/Identity.js +2 -0
  38. package/dist/identity/api/IdentityService.d.ts +9 -0
  39. package/dist/identity/api/IdentityService.js +27 -0
  40. package/dist/identity/api/Profile.d.ts +10 -0
  41. package/dist/identity/api/Profile.js +2 -0
  42. package/dist/identity/api/ProfileService.d.ts +12 -0
  43. package/dist/identity/api/ProfileService.js +27 -0
  44. package/dist/identity/api/index.d.ts +4 -0
  45. package/dist/identity/api/index.js +20 -0
  46. package/dist/identity/auth0/Auth0IdentityService.d.ts +9 -0
  47. package/dist/identity/auth0/Auth0IdentityService.js +27 -0
  48. package/dist/identity/auth0/Auth0Profile.d.ts +30 -0
  49. package/dist/identity/auth0/Auth0Profile.js +57 -0
  50. package/dist/identity/auth0/Auth0ProfileService.d.ts +21 -0
  51. package/dist/identity/auth0/Auth0ProfileService.js +69 -0
  52. package/dist/identity/auth0/index.d.ts +2 -0
  53. package/dist/identity/auth0/index.js +18 -0
  54. package/dist/identity/client/ClientProfile.d.ts +27 -0
  55. package/dist/identity/client/ClientProfile.js +31 -0
  56. package/dist/identity/client/IdentityContainer.d.ts +12 -0
  57. package/dist/identity/client/IdentityContainer.js +23 -0
  58. package/dist/identity/client/IdentityContext.d.ts +8 -0
  59. package/dist/identity/client/IdentityContext.js +6 -0
  60. package/dist/identity/client/index.d.ts +3 -0
  61. package/dist/identity/client/index.js +19 -0
  62. package/dist/identity/client/useIdentity.d.ts +2 -0
  63. package/dist/identity/client/useIdentity.js +9 -0
  64. package/dist/identity/client/useProfile.d.ts +2 -0
  65. package/dist/identity/client/useProfile.js +9 -0
  66. package/dist/identity/index.d.ts +3 -0
  67. package/dist/identity/index.js +19 -0
  68. package/dist/identity/server/IdentityProvider.d.ts +5 -0
  69. package/dist/identity/server/IdentityProvider.js +29 -0
  70. package/dist/identity/server/index.d.ts +1 -0
  71. package/dist/identity/server/index.js +17 -0
  72. package/dist/index.d.ts +5 -0
  73. package/dist/index.js +21 -0
  74. package/dist/ip/index.d.ts +1 -0
  75. package/dist/ip/index.js +17 -0
  76. package/dist/ip/useIpAddress.d.ts +1 -0
  77. package/dist/ip/useIpAddress.js +69 -0
  78. package/dist/leadgen/AbstractPipeDriveAdapter.d.ts +27 -0
  79. package/dist/leadgen/AbstractPipeDriveAdapter.js +43 -0
  80. package/dist/leadgen/ConfigPipeDriveAdapter.d.ts +18 -0
  81. package/dist/leadgen/ConfigPipeDriveAdapter.js +60 -0
  82. package/dist/leadgen/MockPipedrive.d.ts +16 -0
  83. package/dist/leadgen/MockPipedrive.js +32 -0
  84. package/dist/leadgen/PipedriveClient.d.ts +40 -0
  85. package/dist/leadgen/PipedriveClient.js +223 -0
  86. package/dist/leadgen/index.d.ts +4 -0
  87. package/dist/leadgen/index.js +20 -0
  88. package/dist/server.d.ts +4 -0
  89. package/dist/server.js +20 -0
  90. package/package.json +52 -0
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PipedriveClient = void 0;
4
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
5
+ // class
6
+ class PipedriveClient {
7
+ constructor({ apiKey, marketingStatusEnabled = false }) {
8
+ // initialize instance variables
9
+ this._apiKey = apiKey;
10
+ this._marketingStatusEnabled = marketingStatusEnabled;
11
+ }
12
+ async upsertPerson(data) {
13
+ var _a, _b, _c, _d;
14
+ console.debug('[Pipedrive.ts] upsert person');
15
+ // lookup person
16
+ const searchResponse = await this.send({
17
+ path: '/persons/search',
18
+ method: 'GET',
19
+ params: {
20
+ fields: 'email',
21
+ term: data.email,
22
+ exact_match: true
23
+ }
24
+ });
25
+ // fail if there request failed
26
+ if (!searchResponse.success) {
27
+ console.error('[Pipedrive.ts] error: Failed to lookup person');
28
+ throw new funnel_core_1.DependencyError('Failed to lookup person');
29
+ }
30
+ // update if person exists
31
+ const { item: existingPerson } = (_c = ((_b = (_a = searchResponse.data) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [])[0]) !== null && _c !== void 0 ? _c : {};
32
+ if (existingPerson && existingPerson.id) {
33
+ // get person's details (needed for marketing_status and current labels)
34
+ console.debug('[Pipedrive.ts] Getting person details');
35
+ const personDetails = await this.send({
36
+ path: `/persons/${existingPerson.id}`,
37
+ method: 'GET',
38
+ // only fetch marketingStatus if its enabled
39
+ params: this._marketingStatusEnabled ? { include_fields: 'marketing_status' } : {}
40
+ });
41
+ if (!personDetails.success) {
42
+ console.error('[Pipedrive.ts] Error: Failed to get person details');
43
+ throw new funnel_core_1.DependencyError(`Failed to get details of person "${existingPerson.id}" for account ${data.email}`);
44
+ }
45
+ // extract some existing data on person
46
+ const { label_ids, marketing_status: currentMarketingStatus } = personDetails.data;
47
+ // determine updated marketing status
48
+ // pipedrive's marketing status is a state machine,
49
+ // so you need to know the person's previous state
50
+ const updatedMarketingStatus = data.marketingStatus === 'subscribed' ? 'subscribed'
51
+ : currentMarketingStatus === 'subscribed' ? 'unsubscribed'
52
+ : undefined;
53
+ // dont include duplicate label ids
54
+ const newLabelIds = ((_d = data.label_ids) !== null && _d !== void 0 ? _d : []).filter((labelId) => !label_ids.includes(labelId));
55
+ // update labels if there is any
56
+ const customData = Object.assign({}, data.customData);
57
+ // finally do update request
58
+ console.debug('[Pipedrive.ts] Updating new person');
59
+ const updateResponse = await this.send({
60
+ path: `/persons/${existingPerson.id}`,
61
+ method: 'PATCH',
62
+ body: Object.assign({ emails: [{ value: data.email, primary: true }], 'marketing_status': updatedMarketingStatus, 'label_ids': [...label_ids, ...newLabelIds], 'owner_id': data.ownerId }, customData)
63
+ });
64
+ // fail if the add didn't take
65
+ if (!updateResponse.success) {
66
+ console.error('[Pipedrive.ts] Failed to update person');
67
+ throw new funnel_core_1.DependencyError(`Failed to update existing person "${existingPerson.id}" for account ${data.email}`);
68
+ }
69
+ console.debug('[Pipedrive.ts] person is updated');
70
+ return updateResponse;
71
+ }
72
+ // or add person
73
+ else {
74
+ console.debug('[Pipedrive.ts] Adding new person');
75
+ // only responsible for opting into marketing, not opting out, when adding a person
76
+ const marketingStatus = data.marketingStatus === 'subscribed' ? 'subscribed' : undefined;
77
+ const body = Object.assign({ emails: [{ value: data.email, primary: true }], phones: data.phones, 'marketing_status': marketingStatus, 'label_ids': data.label_ids, 'owner_id': data.ownerId }, data.customData);
78
+ const addResponse = await this.send({
79
+ path: '/persons',
80
+ method: 'POST',
81
+ body
82
+ });
83
+ // fail if the add didn't take
84
+ if (!addResponse.success) {
85
+ console.error('[Pipedrive.ts] Failed add update person');
86
+ throw new funnel_core_1.DependencyError('Failed to add new person');
87
+ }
88
+ return addResponse;
89
+ }
90
+ console.debug('[Pipedrive.ts] Upserting new person complete');
91
+ }
92
+ async captureNote(personId, content) {
93
+ console.debug('[PipedriveClient] capturing note', content);
94
+ // build body
95
+ const body = {
96
+ content,
97
+ person_id: personId
98
+ };
99
+ // capture note
100
+ const captureResponse = await this.send({
101
+ path: '/notes',
102
+ method: 'POST',
103
+ body,
104
+ version: 'v1'
105
+ });
106
+ // fail if the capturing note didn't take
107
+ if (!captureResponse.success) {
108
+ console.error('[Pipedrive.ts] Failed tp capture note');
109
+ throw new funnel_core_1.DependencyError('Failed to capture note');
110
+ }
111
+ }
112
+ async captureOrganization(personId, organizationName) {
113
+ var _a, _b, _c;
114
+ let orgId;
115
+ // check if org already exists
116
+ const searchResponse = await this.send({
117
+ path: '/organizations/search',
118
+ method: 'GET',
119
+ params: {
120
+ fields: 'name',
121
+ term: organizationName,
122
+ exact_match: true
123
+ }
124
+ });
125
+ // throw if org lookup fails
126
+ if (!searchResponse.success) {
127
+ console.error('[Pipedrive.ts] error: Failed to lookup organization');
128
+ throw new funnel_core_1.DependencyError('Failed to lookup organization');
129
+ }
130
+ // if org does not exist, create and use newly created id
131
+ const { item: existingOrg } = (_c = ((_b = (_a = searchResponse.data) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [])[0]) !== null && _c !== void 0 ? _c : {};
132
+ if (!existingOrg) {
133
+ const addResponse = await this.send({
134
+ path: '/organizations',
135
+ method: 'POST',
136
+ body: {
137
+ name: organizationName
138
+ }
139
+ });
140
+ // throw if adding org fails
141
+ if (!addResponse.success) {
142
+ console.error('[Pipedrive.ts] error: Failed to add organization');
143
+ throw new funnel_core_1.DependencyError('Failed to lookup organization');
144
+ }
145
+ orgId = addResponse.data.id;
146
+ }
147
+ // otherwise use existing org
148
+ else {
149
+ orgId = existingOrg.id;
150
+ }
151
+ // append organization to person by id
152
+ const updateResponse = await this.send({
153
+ path: `/persons/${personId}`,
154
+ method: 'PATCH',
155
+ body: {
156
+ 'org_id': orgId,
157
+ }
158
+ });
159
+ // throw if update fails
160
+ if (!updateResponse.success) {
161
+ console.error('[Pipedrive.ts] error: Failed to update person with organization');
162
+ throw new funnel_core_1.DependencyError('Failed to lookup organization');
163
+ }
164
+ }
165
+ async send({ path, method, params = {}, body, version = 'v2' }) {
166
+ var _a;
167
+ // create url
168
+ const url = new URL(`/api/${version}${path}`, 'https://api.pipedrive.com');
169
+ const urlParams = url.searchParams;
170
+ urlParams.set('api_token', this._apiKey);
171
+ Object.entries(params).forEach(([name, value]) => urlParams.set(name, serializeParamValue(value)));
172
+ console.debug(`[Pipedrive.ts] sending [${method}] `, { url: url.href });
173
+ // send request
174
+ let response;
175
+ try {
176
+ response = await fetch(url.href, {
177
+ method,
178
+ headers: {
179
+ 'Accept': 'application/json',
180
+ 'Content-Type': 'application/json'
181
+ },
182
+ body: body ? JSON.stringify(body) : undefined
183
+ });
184
+ }
185
+ catch (e) {
186
+ console.error(`[Pipedrive.ts] Error: ${e}`);
187
+ }
188
+ if (response) {
189
+ // throw on failure
190
+ if (!response.ok) {
191
+ console.error('Pipedrive error', await response.json());
192
+ throw new funnel_core_1.DependencyError(`Pipedrive request failed: ${response.status}/${(_a = response.statusText) !== null && _a !== void 0 ? _a : 'unknown'}`);
193
+ }
194
+ // parse response
195
+ const json = await response.json();
196
+ // failed if response has no success
197
+ if (json.success !== true) {
198
+ throw new funnel_core_1.DependencyError('Pipedrive request failed');
199
+ }
200
+ // otherwise, return data
201
+ console.debug(`[Pipedrive.ts] Successful request [${method}] `, { url: url.href });
202
+ return json;
203
+ }
204
+ throw new funnel_core_1.DependencyError('Unknown pipedrive error');
205
+ }
206
+ }
207
+ exports.PipedriveClient = PipedriveClient;
208
+ function serializeParamValue(param) {
209
+ // recurse for arrays
210
+ if (Array.isArray(param)) {
211
+ return param.map(serializeParamValue)
212
+ .filter(funnel_core_1.Value.isDefined)
213
+ .join(',');
214
+ }
215
+ // handle date
216
+ else if (funnel_core_1.Value.isDate(param)) {
217
+ return param.toISOString();
218
+ }
219
+ // or handle raw value
220
+ else {
221
+ return String(param);
222
+ }
223
+ }
@@ -0,0 +1,4 @@
1
+ export * from './AbstractPipeDriveAdapter';
2
+ export * from './ConfigPipeDriveAdapter';
3
+ export * from './MockPipedrive';
4
+ export * from './PipedriveClient';
@@ -0,0 +1,20 @@
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("./AbstractPipeDriveAdapter"), exports);
18
+ __exportStar(require("./ConfigPipeDriveAdapter"), exports);
19
+ __exportStar(require("./MockPipedrive"), exports);
20
+ __exportStar(require("./PipedriveClient"), exports);
@@ -0,0 +1,4 @@
1
+ export * from './captcha';
2
+ export * from './consent/ConsentActions';
3
+ export * from './identity';
4
+ export * from './leadgen';
package/dist/server.js ADDED
@@ -0,0 +1,20 @@
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("./captcha"), exports);
18
+ __exportStar(require("./consent/ConsentActions"), exports);
19
+ __exportStar(require("./identity"), exports);
20
+ __exportStar(require("./leadgen"), exports);
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@nascentdigital/funnel-services",
3
+ "version": "4.4.18",
4
+ "publishConfig": {
5
+ "registry": "https://registry.npmjs.org/",
6
+ "access": "restricted"
7
+ },
8
+ "repository": {
9
+ "url": "git+https://github.com/nascentdigital/funnel.git",
10
+ "directory": "libs/services"
11
+ },
12
+ "main": "dist/index.js",
13
+ "exports": {
14
+ ".": "./dist/index.js",
15
+ "./server": "./dist/server.js"
16
+ },
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "engines": {
22
+ "node": ">=22.0.0"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc -P tsconfig.build.json",
26
+ "clean": "rimraf -I dist"
27
+ },
28
+ "peerDependencies": {
29
+ "@nascentdigital/funnel-core": "*",
30
+ "@nascentdigital/funnel-ui": "*",
31
+ "next": "^15",
32
+ "react": "^19",
33
+ "react-dom": "^19"
34
+ },
35
+ "dependencies": {
36
+ "@auth0/nextjs-auth0": "^4.15.0",
37
+ "auth0": "^5.3.1",
38
+ "rxjs": "^7",
39
+ "server-only": "^0",
40
+ "vanilla-cookieconsent": "^3",
41
+ "web-push": "^3"
42
+ },
43
+ "devDependencies": {
44
+ "@types/request-ip": "^0",
45
+ "@types/web-push": "^3",
46
+ "next": "^15",
47
+ "react": "^19",
48
+ "react-dom": "^19",
49
+ "type-fest": "^4"
50
+ },
51
+ "gitHead": "d1bfd4468426b7326bd9662cd169242867025f5e"
52
+ }