strapi-plugin-hubspot 0.16.3 → 0.16.5
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/CHANGELOG.md +18 -0
- package/dist/_chunks/{Forms-BBaw53Tz.mjs → Forms-DyV6KyiO.mjs} +20 -6
- package/dist/_chunks/{Forms-CIJrUB_n.js → Forms-uUN4XjhW.js} +20 -6
- package/dist/_chunks/{HubspotFormInput-DSTuQ_bx.js → HubspotFormInput-BkWat_wu.js} +1 -1
- package/dist/_chunks/{HubspotFormInput-DIo6hCNz.mjs → HubspotFormInput-DEXPX-6j.mjs} +1 -1
- package/dist/_chunks/{HubspotObjectInput-BIqC8tl2.js → HubspotObjectInput-CFDYW-TM.js} +3 -3
- package/dist/_chunks/{HubspotObjectInput-BA16dswz.mjs → HubspotObjectInput-DL8fYK2x.mjs} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-C77Op1Wm.js → HubspotPropertyInput-CFMkbQeT.js} +3 -3
- package/dist/_chunks/{HubspotPropertyInput-Dsn7ikop.mjs → HubspotPropertyInput-WU5FMJj3.mjs} +3 -3
- package/dist/_chunks/{Settings-PVhJVPqq.js → Settings-B_hhdpHa.js} +2 -2
- package/dist/_chunks/{Settings-DxX9Uh_2.mjs → Settings-CiXEps_C.mjs} +2 -2
- package/dist/_chunks/{en-Djd3TID0.mjs → en-BIUBYzHv.mjs} +5 -1
- package/dist/_chunks/{en-sfzopB5K.js → en-CFhEtgZJ.js} +5 -1
- package/dist/_chunks/{fr-C7t1elmR.mjs → fr-CMYcnFH0.mjs} +5 -1
- package/dist/_chunks/{fr-sF5Josfh.js → fr-zdUuuV0M.js} +5 -1
- package/dist/_chunks/{index-B8GYi6sw.mjs → index-BeBn7bJa.mjs} +6 -6
- package/dist/_chunks/{index-XEuSPuUj.js → index-CG_WQzSa.js} +6 -6
- package/dist/_chunks/{objectLabels-wBwfLdZt.js → objectLabels-BGq-Ypgn.js} +1 -1
- package/dist/_chunks/{objectLabels-DybqhBdT.mjs → objectLabels-CS_0QCNz.mjs} +1 -1
- package/dist/_chunks/{useHubspotSchema-WvgW3od8.js → useHubspotSchema-BZP2qkAu.js} +1 -1
- package/dist/_chunks/{useHubspotSchema-DtcHHUOb.mjs → useHubspotSchema-CP7LRdzO.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/builder/types.d.ts +1 -1
- package/dist/server/index.js +99 -25
- package/dist/server/index.mjs +99 -25
- package/dist/server/src/hsforms.d.ts +53 -7
- package/dist/server/src/importHubspot.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.16.5 — 2026-09-23
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Admin TypeScript build failed on Submissions (`unknown` used as ReactNode).
|
|
9
|
+
Same conversion-fail behaviour as 0.16.4; this is the first npm publish of
|
|
10
|
+
that fix.
|
|
11
|
+
|
|
12
|
+
## 0.16.4 — 2026-09-23
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- A linked HubSpot form that refused the Forms API (GDPR communications,
|
|
16
|
+
CAPTCHA, extra required fields) silently fell back to a CRM upsert + note,
|
|
17
|
+
so the contact looked updated with no native submission. The submit now
|
|
18
|
+
sends `objectTypeId`, the form's communication consents, skips the
|
|
19
|
+
email-only retry when HubSpot requires other fields, and refuses CAPTCHA
|
|
20
|
+
forms with a stored error. Strapi Submissions distinguish **Conversion**
|
|
21
|
+
vs **Contact only**.
|
|
22
|
+
|
|
5
23
|
## 0.16.3 — 2026-09-22
|
|
6
24
|
|
|
7
25
|
### Changed
|
|
@@ -5,12 +5,12 @@ import { u as useIntl } from "./index-CEh8vkxY.mjs";
|
|
|
5
5
|
import { Typography, Flex, Box, SingleSelect, SingleSelectOption, MultiSelect, MultiSelectOption, TextInput, IconButton, Button, Combobox, ComboboxOption, Field, Textarea, Checkbox, Divider, Loader, Badge, Table, Thead, Tr, Th, Tbody, Td, Modal } from "@strapi/design-system";
|
|
6
6
|
import { Trash, Plus, ArrowClockwise, ArrowLeft, Drag, ArrowUp, ArrowDown, List, Duplicate, Download } from "@strapi/icons";
|
|
7
7
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
8
|
-
import { g as getTranslation, P as PLUGIN_ID } from "./index-
|
|
8
|
+
import { g as getTranslation, P as PLUGIN_ID } from "./index-BeBn7bJa.mjs";
|
|
9
9
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, useDroppable, closestCorners } from "@dnd-kit/core";
|
|
10
10
|
import { arrayMove, sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-kit/sortable";
|
|
11
11
|
import { CSS } from "@dnd-kit/utilities";
|
|
12
|
-
import { o as objectLabel } from "./objectLabels-
|
|
13
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
12
|
+
import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
|
|
13
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
|
|
14
14
|
const OPERATORS = [
|
|
15
15
|
"eq",
|
|
16
16
|
"neq",
|
|
@@ -705,6 +705,7 @@ const FormEditor = () => {
|
|
|
705
705
|
const locale = searchParams.get("locale") ?? void 0;
|
|
706
706
|
const [entry, setEntry] = React.useState(null);
|
|
707
707
|
const [published, setPublished] = React.useState(false);
|
|
708
|
+
const [publishedHubspotFormId, setPublishedHubspotFormId] = React.useState(null);
|
|
708
709
|
const [locales, setLocales] = React.useState([]);
|
|
709
710
|
const [selection, setSelection] = React.useState({ kind: "form" });
|
|
710
711
|
const [dirty, setDirty] = React.useState(false);
|
|
@@ -741,6 +742,7 @@ const FormEditor = () => {
|
|
|
741
742
|
if (cancelled) return;
|
|
742
743
|
setEntry(data.form);
|
|
743
744
|
setPublished(data.published);
|
|
745
|
+
setPublishedHubspotFormId(data.publishedHubspotFormId ?? null);
|
|
744
746
|
setDirty(false);
|
|
745
747
|
}).catch(async () => {
|
|
746
748
|
if (cancelled || !locale) return;
|
|
@@ -851,6 +853,7 @@ const FormEditor = () => {
|
|
|
851
853
|
try {
|
|
852
854
|
const { data } = await post(`/${PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
|
|
853
855
|
setPublished(true);
|
|
856
|
+
setPublishedHubspotFormId(entry.hubspotFormId ?? null);
|
|
854
857
|
setErrors([]);
|
|
855
858
|
setProblems([]);
|
|
856
859
|
const added = Array.isArray(data?.addedFields) ? data.addedFields.length : 0;
|
|
@@ -1339,7 +1342,10 @@ const FormEditor = () => {
|
|
|
1339
1342
|
),
|
|
1340
1343
|
onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
|
|
1341
1344
|
children: [
|
|
1342
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t(
|
|
1345
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t(
|
|
1346
|
+
"editor.hubspot-form-none",
|
|
1347
|
+
"Default marketing form (Settings) — contact only if none is set"
|
|
1348
|
+
) }),
|
|
1343
1349
|
entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsx(SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
|
|
1344
1350
|
hsForms.map((f) => /* @__PURE__ */ jsx(SingleSelectOption, { value: f.id, children: f.name }, f.id))
|
|
1345
1351
|
]
|
|
@@ -1355,6 +1361,10 @@ const FormEditor = () => {
|
|
|
1355
1361
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1356
1362
|
"editor.hubspot-form-hint",
|
|
1357
1363
|
"Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay."
|
|
1364
|
+
) }),
|
|
1365
|
+
published && (entry.hubspotFormId || "") !== (publishedHubspotFormId || "") && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: t(
|
|
1366
|
+
"editor.hubspot-form-unpublished",
|
|
1367
|
+
"The live site still uses the previously published HubSpot form. Publish to apply this link."
|
|
1358
1368
|
) })
|
|
1359
1369
|
] }),
|
|
1360
1370
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
@@ -1764,7 +1774,7 @@ const Submissions = () => {
|
|
|
1764
1774
|
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { children: row.formTitle || row.form }) }),
|
|
1765
1775
|
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: row.email || "—" }) }),
|
|
1766
1776
|
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", ellipsis: true, children: preview(row.values) }) }),
|
|
1767
|
-
/* @__PURE__ */ jsx(Td, { children: row.
|
|
1777
|
+
/* @__PURE__ */ jsx(Td, { children: row.meta?.hubspotConversion === true || row.meta?.hubspotConversion === "true" ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.converted", "Conversion") }) : row.hubspotSynced ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.contact-only", "Contact only") }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
|
|
1768
1778
|
]
|
|
1769
1779
|
},
|
|
1770
1780
|
row.documentId
|
|
@@ -1800,9 +1810,13 @@ const Submissions = () => {
|
|
|
1800
1810
|
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: key }),
|
|
1801
1811
|
/* @__PURE__ */ jsx(Typography, { tag: "p", children: String(value) })
|
|
1802
1812
|
] }, key)),
|
|
1803
|
-
selected.meta?.pagePath && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1813
|
+
typeof selected.meta?.pagePath === "string" && selected.meta.pagePath && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1804
1814
|
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: t("submissions.meta-page", "Submitted from") }),
|
|
1805
1815
|
/* @__PURE__ */ jsx(Typography, { tag: "p", children: selected.meta.pagePath })
|
|
1816
|
+
] }),
|
|
1817
|
+
typeof selected.meta?.hubspotError === "string" && selected.meta.hubspotError && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1818
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "danger600", tag: "p", children: t("submissions.conversion-error", "Conversion failed") }),
|
|
1819
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", children: selected.meta.hubspotError })
|
|
1806
1820
|
] })
|
|
1807
1821
|
] }) })
|
|
1808
1822
|
] }) })
|
|
@@ -7,12 +7,12 @@ const index = require("./index-DkTxsEqL.js");
|
|
|
7
7
|
const designSystem = require("@strapi/design-system");
|
|
8
8
|
const icons = require("@strapi/icons");
|
|
9
9
|
const admin = require("@strapi/strapi/admin");
|
|
10
|
-
const index$1 = require("./index-
|
|
10
|
+
const index$1 = require("./index-CG_WQzSa.js");
|
|
11
11
|
const core = require("@dnd-kit/core");
|
|
12
12
|
const sortable = require("@dnd-kit/sortable");
|
|
13
13
|
const utilities = require("@dnd-kit/utilities");
|
|
14
|
-
const objectLabels = require("./objectLabels-
|
|
15
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
14
|
+
const objectLabels = require("./objectLabels-BGq-Ypgn.js");
|
|
15
|
+
const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.js");
|
|
16
16
|
function _interopNamespace(e) {
|
|
17
17
|
if (e && e.__esModule) return e;
|
|
18
18
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -725,6 +725,7 @@ const FormEditor = () => {
|
|
|
725
725
|
const locale = searchParams.get("locale") ?? void 0;
|
|
726
726
|
const [entry, setEntry] = React__namespace.useState(null);
|
|
727
727
|
const [published, setPublished] = React__namespace.useState(false);
|
|
728
|
+
const [publishedHubspotFormId, setPublishedHubspotFormId] = React__namespace.useState(null);
|
|
728
729
|
const [locales, setLocales] = React__namespace.useState([]);
|
|
729
730
|
const [selection, setSelection] = React__namespace.useState({ kind: "form" });
|
|
730
731
|
const [dirty, setDirty] = React__namespace.useState(false);
|
|
@@ -761,6 +762,7 @@ const FormEditor = () => {
|
|
|
761
762
|
if (cancelled) return;
|
|
762
763
|
setEntry(data.form);
|
|
763
764
|
setPublished(data.published);
|
|
765
|
+
setPublishedHubspotFormId(data.publishedHubspotFormId ?? null);
|
|
764
766
|
setDirty(false);
|
|
765
767
|
}).catch(async () => {
|
|
766
768
|
if (cancelled || !locale) return;
|
|
@@ -871,6 +873,7 @@ const FormEditor = () => {
|
|
|
871
873
|
try {
|
|
872
874
|
const { data } = await post(`/${index$1.PLUGIN_ID}/builder/forms/${documentId}/publish${query}`);
|
|
873
875
|
setPublished(true);
|
|
876
|
+
setPublishedHubspotFormId(entry.hubspotFormId ?? null);
|
|
874
877
|
setErrors([]);
|
|
875
878
|
setProblems([]);
|
|
876
879
|
const added = Array.isArray(data?.addedFields) ? data.addedFields.length : 0;
|
|
@@ -1359,7 +1362,10 @@ const FormEditor = () => {
|
|
|
1359
1362
|
),
|
|
1360
1363
|
onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
|
|
1361
1364
|
children: [
|
|
1362
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t(
|
|
1365
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t(
|
|
1366
|
+
"editor.hubspot-form-none",
|
|
1367
|
+
"Default marketing form (Settings) — contact only if none is set"
|
|
1368
|
+
) }),
|
|
1363
1369
|
entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
|
|
1364
1370
|
hsForms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.id, children: f.name }, f.id))
|
|
1365
1371
|
]
|
|
@@ -1375,6 +1381,10 @@ const FormEditor = () => {
|
|
|
1375
1381
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
1376
1382
|
"editor.hubspot-form-hint",
|
|
1377
1383
|
"Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay."
|
|
1384
|
+
) }),
|
|
1385
|
+
published && (entry.hubspotFormId || "") !== (publishedHubspotFormId || "") && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: t(
|
|
1386
|
+
"editor.hubspot-form-unpublished",
|
|
1387
|
+
"The live site still uses the previously published HubSpot form. Publish to apply this link."
|
|
1378
1388
|
) })
|
|
1379
1389
|
] }),
|
|
1380
1390
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
|
|
@@ -1784,7 +1794,7 @@ const Submissions = () => {
|
|
|
1784
1794
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.formTitle || row.form }) }),
|
|
1785
1795
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", children: row.email || "—" }) }),
|
|
1786
1796
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", ellipsis: true, children: preview(row.values) }) }),
|
|
1787
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: row.
|
|
1797
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: row.meta?.hubspotConversion === true || row.meta?.hubspotConversion === "true" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", children: t("submissions.converted", "Conversion") }) : row.hubspotSynced ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.contact-only", "Contact only") }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "warning100", textColor: "warning700", children: t("submissions.not-synced", "Not synced") }) })
|
|
1788
1798
|
]
|
|
1789
1799
|
},
|
|
1790
1800
|
row.documentId
|
|
@@ -1820,9 +1830,13 @@ const Submissions = () => {
|
|
|
1820
1830
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: key }),
|
|
1821
1831
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: String(value) })
|
|
1822
1832
|
] }, key)),
|
|
1823
|
-
selected.meta?.pagePath && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
1833
|
+
typeof selected.meta?.pagePath === "string" && selected.meta.pagePath && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
1824
1834
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", tag: "p", children: t("submissions.meta-page", "Submitted from") }),
|
|
1825
1835
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: selected.meta.pagePath })
|
|
1836
|
+
] }),
|
|
1837
|
+
typeof selected.meta?.hubspotError === "string" && selected.meta.hubspotError && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
1838
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "danger600", tag: "p", children: t("submissions.conversion-error", "Conversion failed") }),
|
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", children: selected.meta.hubspotError })
|
|
1826
1840
|
] })
|
|
1827
1841
|
] }) })
|
|
1828
1842
|
] }) })
|
|
@@ -5,7 +5,7 @@ const React = require("react");
|
|
|
5
5
|
const index = require("./index-DkTxsEqL.js");
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const admin = require("@strapi/strapi/admin");
|
|
8
|
-
const index$1 = require("./index-
|
|
8
|
+
const index$1 = require("./index-CG_WQzSa.js");
|
|
9
9
|
function _interopNamespace(e) {
|
|
10
10
|
if (e && e.__esModule) return e;
|
|
11
11
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { u as useIntl } from "./index-CEh8vkxY.mjs";
|
|
4
4
|
import { Field, Flex, Loader, Combobox, ComboboxOption } from "@strapi/design-system";
|
|
5
5
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
6
|
-
import { P as PLUGIN_ID, g as getTranslation } from "./index-
|
|
6
|
+
import { P as PLUGIN_ID, g as getTranslation } from "./index-BeBn7bJa.mjs";
|
|
7
7
|
const HubspotFormInput = React.forwardRef(
|
|
8
8
|
({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
|
|
9
9
|
const { formatMessage } = useIntl();
|
|
@@ -4,9 +4,9 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
4
4
|
const React = require("react");
|
|
5
5
|
const index = require("./index-DkTxsEqL.js");
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
|
-
const index$1 = require("./index-
|
|
8
|
-
const objectLabels = require("./objectLabels-
|
|
9
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
7
|
+
const index$1 = require("./index-CG_WQzSa.js");
|
|
8
|
+
const objectLabels = require("./objectLabels-BGq-Ypgn.js");
|
|
9
|
+
const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.js");
|
|
10
10
|
function _interopNamespace(e) {
|
|
11
11
|
if (e && e.__esModule) return e;
|
|
12
12
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -2,9 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { u as useIntl } from "./index-CEh8vkxY.mjs";
|
|
4
4
|
import { Field, Flex, Loader, SingleSelect, SingleSelectOption } from "@strapi/design-system";
|
|
5
|
-
import { g as getTranslation } from "./index-
|
|
6
|
-
import { o as objectLabel } from "./objectLabels-
|
|
7
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
5
|
+
import { g as getTranslation } from "./index-BeBn7bJa.mjs";
|
|
6
|
+
import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
|
|
7
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
|
|
8
8
|
const HubspotObjectInput = React.forwardRef(
|
|
9
9
|
({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
|
|
10
10
|
const intl = useIntl();
|
|
@@ -6,9 +6,9 @@ const index = require("./index-DkTxsEqL.js");
|
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const icons = require("@strapi/icons");
|
|
8
8
|
const admin = require("@strapi/strapi/admin");
|
|
9
|
-
const index$1 = require("./index-
|
|
10
|
-
const objectLabels = require("./objectLabels-
|
|
11
|
-
const useHubspotSchema = require("./useHubspotSchema-
|
|
9
|
+
const index$1 = require("./index-CG_WQzSa.js");
|
|
10
|
+
const objectLabels = require("./objectLabels-BGq-Ypgn.js");
|
|
11
|
+
const useHubspotSchema = require("./useHubspotSchema-BZP2qkAu.js");
|
|
12
12
|
function _interopNamespace(e) {
|
|
13
13
|
if (e && e.__esModule) return e;
|
|
14
14
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
package/dist/_chunks/{HubspotPropertyInput-Dsn7ikop.mjs → HubspotPropertyInput-WU5FMJj3.mjs}
RENAMED
|
@@ -4,9 +4,9 @@ import { u as useIntl } from "./index-CEh8vkxY.mjs";
|
|
|
4
4
|
import { Field, Flex, Loader, Combobox, ComboboxOption, IconButton, Button, Typography, Link } from "@strapi/design-system";
|
|
5
5
|
import { ArrowClockwise } from "@strapi/icons";
|
|
6
6
|
import { useField } from "@strapi/strapi/admin";
|
|
7
|
-
import { g as getTranslation } from "./index-
|
|
8
|
-
import { o as objectLabel } from "./objectLabels-
|
|
9
|
-
import { u as useHubspotSchema } from "./useHubspotSchema-
|
|
7
|
+
import { g as getTranslation } from "./index-BeBn7bJa.mjs";
|
|
8
|
+
import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
|
|
9
|
+
import { u as useHubspotSchema } from "./useHubspotSchema-CP7LRdzO.mjs";
|
|
10
10
|
const oneLine = {
|
|
11
11
|
display: "block",
|
|
12
12
|
whiteSpace: "nowrap",
|
|
@@ -5,9 +5,9 @@ const React = require("react");
|
|
|
5
5
|
const index = require("./index-DkTxsEqL.js");
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const admin = require("@strapi/strapi/admin");
|
|
8
|
-
const index$1 = require("./index-
|
|
8
|
+
const index$1 = require("./index-CG_WQzSa.js");
|
|
9
9
|
const reactRouterDom = require("react-router-dom");
|
|
10
|
-
const objectLabels = require("./objectLabels-
|
|
10
|
+
const objectLabels = require("./objectLabels-BGq-Ypgn.js");
|
|
11
11
|
function _interopNamespace(e) {
|
|
12
12
|
if (e && e.__esModule) return e;
|
|
13
13
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -3,9 +3,9 @@ import * as React from "react";
|
|
|
3
3
|
import { u as useIntl } from "./index-CEh8vkxY.mjs";
|
|
4
4
|
import { Flex, Divider, Typography, Button, Box, Link, Badge, Loader, Field, SingleSelect, SingleSelectOption, Checkbox } from "@strapi/design-system";
|
|
5
5
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
6
|
-
import { g as getTranslation, P as PLUGIN_ID } from "./index-
|
|
6
|
+
import { g as getTranslation, P as PLUGIN_ID } from "./index-BeBn7bJa.mjs";
|
|
7
7
|
import { Link as Link$1 } from "react-router-dom";
|
|
8
|
-
import { o as objectLabel } from "./objectLabels-
|
|
8
|
+
import { o as objectLabel } from "./objectLabels-CS_0QCNz.mjs";
|
|
9
9
|
const AuditSection = ({ configured }) => {
|
|
10
10
|
const intl = useIntl();
|
|
11
11
|
const { formatMessage } = intl;
|
|
@@ -163,8 +163,9 @@ const en = {
|
|
|
163
163
|
"editor.form-success": "Success message",
|
|
164
164
|
"editor.hubspot-form": "HubSpot marketing form",
|
|
165
165
|
"editor.hubspot-form-placeholder": "Pick a form of the connected portal",
|
|
166
|
-
"editor.hubspot-form-none": "
|
|
166
|
+
"editor.hubspot-form-none": "Default marketing form (Settings) — contact only if none is set",
|
|
167
167
|
"editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay.",
|
|
168
|
+
"editor.hubspot-form-unpublished": "The live site still uses the previously published HubSpot form. Publish to apply this link.",
|
|
168
169
|
"editor.resync": "Resync from HubSpot",
|
|
169
170
|
"editor.resynced": "Resynced from HubSpot — {updated, plural, one {# field updated} other {# fields updated}}, {added, plural, one {# added} other {# added}}.",
|
|
170
171
|
"editor.resynced-gaps": "Resynced from HubSpot — {updated, plural, one {# updated} other {# updated}}, {added, plural, one {# added} other {# added}}, {skipped, plural, one {# skipped} other {# skipped}}.",
|
|
@@ -269,6 +270,9 @@ const en = {
|
|
|
269
270
|
"submissions.col-answers": "Answers",
|
|
270
271
|
"submissions.col-crm": "CRM",
|
|
271
272
|
"submissions.synced": "Synced",
|
|
273
|
+
"submissions.converted": "Conversion",
|
|
274
|
+
"submissions.contact-only": "Contact only",
|
|
275
|
+
"submissions.conversion-error": "Conversion failed",
|
|
272
276
|
"submissions.not-synced": "Not synced",
|
|
273
277
|
"submissions.count": "{total, plural, one {# submission} other {# submissions}}",
|
|
274
278
|
"submissions.prev": "Previous",
|
|
@@ -165,8 +165,9 @@ const en = {
|
|
|
165
165
|
"editor.form-success": "Success message",
|
|
166
166
|
"editor.hubspot-form": "HubSpot marketing form",
|
|
167
167
|
"editor.hubspot-form-placeholder": "Pick a form of the connected portal",
|
|
168
|
-
"editor.hubspot-form-none": "
|
|
168
|
+
"editor.hubspot-form-none": "Default marketing form (Settings) — contact only if none is set",
|
|
169
169
|
"editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. After you change the form in HubSpot, use Resync from HubSpot — mapped fields update in place, new ones are appended, your steps stay.",
|
|
170
|
+
"editor.hubspot-form-unpublished": "The live site still uses the previously published HubSpot form. Publish to apply this link.",
|
|
170
171
|
"editor.resync": "Resync from HubSpot",
|
|
171
172
|
"editor.resynced": "Resynced from HubSpot — {updated, plural, one {# field updated} other {# fields updated}}, {added, plural, one {# added} other {# added}}.",
|
|
172
173
|
"editor.resynced-gaps": "Resynced from HubSpot — {updated, plural, one {# updated} other {# updated}}, {added, plural, one {# added} other {# added}}, {skipped, plural, one {# skipped} other {# skipped}}.",
|
|
@@ -271,6 +272,9 @@ const en = {
|
|
|
271
272
|
"submissions.col-answers": "Answers",
|
|
272
273
|
"submissions.col-crm": "CRM",
|
|
273
274
|
"submissions.synced": "Synced",
|
|
275
|
+
"submissions.converted": "Conversion",
|
|
276
|
+
"submissions.contact-only": "Contact only",
|
|
277
|
+
"submissions.conversion-error": "Conversion failed",
|
|
274
278
|
"submissions.not-synced": "Not synced",
|
|
275
279
|
"submissions.count": "{total, plural, one {# submission} other {# submissions}}",
|
|
276
280
|
"submissions.prev": "Previous",
|
|
@@ -163,8 +163,9 @@ const fr = {
|
|
|
163
163
|
"editor.form-success": "Message de succès",
|
|
164
164
|
"editor.hubspot-form": "Formulaire marketing HubSpot",
|
|
165
165
|
"editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
|
|
166
|
-
"editor.hubspot-form-none": "
|
|
166
|
+
"editor.hubspot-form-none": "Formulaire marketing par défaut (Réglages) — contact seul si aucun n'est défini",
|
|
167
167
|
"editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Après une modification dans HubSpot, utilisez Resynchroniser — les champs mappés se mettent à jour sur place, les nouveaux s’ajoutent, vos étapes restent.",
|
|
168
|
+
"editor.hubspot-form-unpublished": "Le site live utilise encore le formulaire HubSpot précédemment publié. Publiez pour appliquer ce lien.",
|
|
168
169
|
"editor.resync": "Resynchroniser depuis HubSpot",
|
|
169
170
|
"editor.resynced": "Resynchronisé depuis HubSpot — {updated, plural, one {# champ mis à jour} other {# champs mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}.",
|
|
170
171
|
"editor.resynced-gaps": "Resynchronisé depuis HubSpot — {updated, plural, one {# mis à jour} other {# mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}, {skipped, plural, one {# écarté} other {# écartés}}.",
|
|
@@ -269,6 +270,9 @@ const fr = {
|
|
|
269
270
|
"submissions.col-answers": "Réponses",
|
|
270
271
|
"submissions.col-crm": "CRM",
|
|
271
272
|
"submissions.synced": "Synchronisée",
|
|
273
|
+
"submissions.converted": "Conversion",
|
|
274
|
+
"submissions.contact-only": "Contact seul",
|
|
275
|
+
"submissions.conversion-error": "Conversion échouée",
|
|
272
276
|
"submissions.not-synced": "Non synchronisée",
|
|
273
277
|
"submissions.count": "{total, plural, one {# soumission} other {# soumissions}}",
|
|
274
278
|
"submissions.prev": "Précédent",
|
|
@@ -165,8 +165,9 @@ const fr = {
|
|
|
165
165
|
"editor.form-success": "Message de succès",
|
|
166
166
|
"editor.hubspot-form": "Formulaire marketing HubSpot",
|
|
167
167
|
"editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
|
|
168
|
-
"editor.hubspot-form-none": "
|
|
168
|
+
"editor.hubspot-form-none": "Formulaire marketing par défaut (Réglages) — contact seul si aucun n'est défini",
|
|
169
169
|
"editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Après une modification dans HubSpot, utilisez Resynchroniser — les champs mappés se mettent à jour sur place, les nouveaux s’ajoutent, vos étapes restent.",
|
|
170
|
+
"editor.hubspot-form-unpublished": "Le site live utilise encore le formulaire HubSpot précédemment publié. Publiez pour appliquer ce lien.",
|
|
170
171
|
"editor.resync": "Resynchroniser depuis HubSpot",
|
|
171
172
|
"editor.resynced": "Resynchronisé depuis HubSpot — {updated, plural, one {# champ mis à jour} other {# champs mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}.",
|
|
172
173
|
"editor.resynced-gaps": "Resynchronisé depuis HubSpot — {updated, plural, one {# mis à jour} other {# mis à jour}}, {added, plural, one {# ajouté} other {# ajoutés}}, {skipped, plural, one {# écarté} other {# écartés}}.",
|
|
@@ -271,6 +272,9 @@ const fr = {
|
|
|
271
272
|
"submissions.col-answers": "Réponses",
|
|
272
273
|
"submissions.col-crm": "CRM",
|
|
273
274
|
"submissions.synced": "Synchronisée",
|
|
275
|
+
"submissions.converted": "Conversion",
|
|
276
|
+
"submissions.contact-only": "Contact seul",
|
|
277
|
+
"submissions.conversion-error": "Conversion échouée",
|
|
274
278
|
"submissions.not-synced": "Non synchronisée",
|
|
275
279
|
"submissions.count": "{total, plural, one {# soumission} other {# soumissions}}",
|
|
276
280
|
"submissions.prev": "Précédent",
|
|
@@ -25,7 +25,7 @@ const index = {
|
|
|
25
25
|
icon: PaperPlane,
|
|
26
26
|
intlLabel: { id: `${PLUGIN_ID}.menu.label`, defaultMessage: "HubSpot Forms" },
|
|
27
27
|
permissions: [{ action: `plugin::${PLUGIN_ID}.forms`, subject: null }],
|
|
28
|
-
Component: async () => (await import("./Forms-
|
|
28
|
+
Component: async () => (await import("./Forms-DyV6KyiO.mjs")).default
|
|
29
29
|
});
|
|
30
30
|
app.customFields.register({
|
|
31
31
|
name: "property",
|
|
@@ -40,7 +40,7 @@ const index = {
|
|
|
40
40
|
defaultMessage: "Picked from the portal's real properties"
|
|
41
41
|
},
|
|
42
42
|
components: {
|
|
43
|
-
Input: async () => import("./HubspotPropertyInput-
|
|
43
|
+
Input: async () => import("./HubspotPropertyInput-WU5FMJj3.mjs")
|
|
44
44
|
},
|
|
45
45
|
// Exposed in the Content-Type Builder. Without this, `objectField` could
|
|
46
46
|
// only be set by hand-editing schema.json — which is not how anyone
|
|
@@ -103,7 +103,7 @@ const index = {
|
|
|
103
103
|
defaultMessage: "Picked from the portal's configured objects"
|
|
104
104
|
},
|
|
105
105
|
components: {
|
|
106
|
-
Input: async () => import("./HubspotObjectInput-
|
|
106
|
+
Input: async () => import("./HubspotObjectInput-DL8fYK2x.mjs")
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
app.customFields.register({
|
|
@@ -119,7 +119,7 @@ const index = {
|
|
|
119
119
|
defaultMessage: "A form built in the HubSpot form builder, stored by slug"
|
|
120
120
|
},
|
|
121
121
|
components: {
|
|
122
|
-
Input: async () => import("./HubspotFormInput-
|
|
122
|
+
Input: async () => import("./HubspotFormInput-DEXPX-6j.mjs")
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
app.createSettingSection(
|
|
@@ -135,7 +135,7 @@ const index = {
|
|
|
135
135
|
// Mirrors the RBAC action registered server-side: a role without it
|
|
136
136
|
// doesn't see the link at all — the routes refuse it anyway.
|
|
137
137
|
permissions: [{ action: `plugin::${PLUGIN_ID}.settings`, subject: null }],
|
|
138
|
-
Component: async () => (await import("./Settings-
|
|
138
|
+
Component: async () => (await import("./Settings-CiXEps_C.mjs")).default
|
|
139
139
|
}
|
|
140
140
|
]
|
|
141
141
|
);
|
|
@@ -145,7 +145,7 @@ const index = {
|
|
|
145
145
|
return Promise.all(
|
|
146
146
|
locales.map(async (locale) => {
|
|
147
147
|
try {
|
|
148
|
-
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-
|
|
148
|
+
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-BIUBYzHv.mjs"), "./translations/fr.json": () => import("./fr-CMYcnFH0.mjs") }), `./translations/${locale}.json`, 3);
|
|
149
149
|
return { data: prefixPluginTranslations(data), locale };
|
|
150
150
|
} catch {
|
|
151
151
|
return { data: {}, locale };
|
|
@@ -26,7 +26,7 @@ const index = {
|
|
|
26
26
|
icon: icons.PaperPlane,
|
|
27
27
|
intlLabel: { id: `${PLUGIN_ID}.menu.label`, defaultMessage: "HubSpot Forms" },
|
|
28
28
|
permissions: [{ action: `plugin::${PLUGIN_ID}.forms`, subject: null }],
|
|
29
|
-
Component: async () => (await Promise.resolve().then(() => require("./Forms-
|
|
29
|
+
Component: async () => (await Promise.resolve().then(() => require("./Forms-uUN4XjhW.js"))).default
|
|
30
30
|
});
|
|
31
31
|
app.customFields.register({
|
|
32
32
|
name: "property",
|
|
@@ -41,7 +41,7 @@ const index = {
|
|
|
41
41
|
defaultMessage: "Picked from the portal's real properties"
|
|
42
42
|
},
|
|
43
43
|
components: {
|
|
44
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-
|
|
44
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-CFMkbQeT.js"))
|
|
45
45
|
},
|
|
46
46
|
// Exposed in the Content-Type Builder. Without this, `objectField` could
|
|
47
47
|
// only be set by hand-editing schema.json — which is not how anyone
|
|
@@ -104,7 +104,7 @@ const index = {
|
|
|
104
104
|
defaultMessage: "Picked from the portal's configured objects"
|
|
105
105
|
},
|
|
106
106
|
components: {
|
|
107
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-
|
|
107
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-CFDYW-TM.js"))
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
app.customFields.register({
|
|
@@ -120,7 +120,7 @@ const index = {
|
|
|
120
120
|
defaultMessage: "A form built in the HubSpot form builder, stored by slug"
|
|
121
121
|
},
|
|
122
122
|
components: {
|
|
123
|
-
Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-
|
|
123
|
+
Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-BkWat_wu.js"))
|
|
124
124
|
}
|
|
125
125
|
});
|
|
126
126
|
app.createSettingSection(
|
|
@@ -136,7 +136,7 @@ const index = {
|
|
|
136
136
|
// Mirrors the RBAC action registered server-side: a role without it
|
|
137
137
|
// doesn't see the link at all — the routes refuse it anyway.
|
|
138
138
|
permissions: [{ action: `plugin::${PLUGIN_ID}.settings`, subject: null }],
|
|
139
|
-
Component: async () => (await Promise.resolve().then(() => require("./Settings-
|
|
139
|
+
Component: async () => (await Promise.resolve().then(() => require("./Settings-B_hhdpHa.js"))).default
|
|
140
140
|
}
|
|
141
141
|
]
|
|
142
142
|
);
|
|
@@ -146,7 +146,7 @@ const index = {
|
|
|
146
146
|
return Promise.all(
|
|
147
147
|
locales.map(async (locale) => {
|
|
148
148
|
try {
|
|
149
|
-
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-
|
|
149
|
+
const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-CFhEtgZJ.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-zdUuuV0M.js")) }), `./translations/${locale}.json`, 3);
|
|
150
150
|
return { data: prefixPluginTranslations(data), locale };
|
|
151
151
|
} catch {
|
|
152
152
|
return { data: {}, locale };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const React = require("react");
|
|
3
3
|
const admin = require("@strapi/strapi/admin");
|
|
4
|
-
const index = require("./index-
|
|
4
|
+
const index = require("./index-CG_WQzSa.js");
|
|
5
5
|
function _interopNamespace(e) {
|
|
6
6
|
if (e && e.__esModule) return e;
|
|
7
7
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { useFetchClient } from "@strapi/strapi/admin";
|
|
3
|
-
import { P as PLUGIN_ID } from "./index-
|
|
3
|
+
import { P as PLUGIN_ID } from "./index-BeBn7bJa.mjs";
|
|
4
4
|
let cached = null;
|
|
5
5
|
let inFlight = null;
|
|
6
6
|
const listeners = /* @__PURE__ */ new Set();
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
|
@@ -103,7 +103,7 @@ export interface SubmissionRowDto {
|
|
|
103
103
|
formTitle?: string | null;
|
|
104
104
|
email?: string | null;
|
|
105
105
|
values: Record<string, string | number | boolean>;
|
|
106
|
-
meta?: Record<string,
|
|
106
|
+
meta?: Record<string, unknown> | null;
|
|
107
107
|
locale?: string | null;
|
|
108
108
|
hubspotSynced?: boolean;
|
|
109
109
|
createdAt?: string;
|
package/dist/server/index.js
CHANGED
|
@@ -1936,6 +1936,59 @@ function formFieldNames(raw) {
|
|
|
1936
1936
|
}
|
|
1937
1937
|
return names;
|
|
1938
1938
|
}
|
|
1939
|
+
function formRequiredNames(raw) {
|
|
1940
|
+
const names = [];
|
|
1941
|
+
for (const group of raw.fieldGroups ?? []) {
|
|
1942
|
+
for (const field of group.fields ?? []) {
|
|
1943
|
+
if (field.name && field.required) names.push(field.name);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
return names;
|
|
1947
|
+
}
|
|
1948
|
+
function parseFormShape(raw) {
|
|
1949
|
+
const legal = raw.legalConsentOptions;
|
|
1950
|
+
const hasLegalConsent = Boolean(
|
|
1951
|
+
legal && typeof legal === "object" && legal.type && legal.type !== "none"
|
|
1952
|
+
);
|
|
1953
|
+
const communications = [];
|
|
1954
|
+
for (const box of legal?.communicationsCheckboxes ?? []) {
|
|
1955
|
+
const id = Number(box.subscriptionTypeId ?? box.communicationTypeId);
|
|
1956
|
+
if (!Number.isFinite(id) || id <= 0) continue;
|
|
1957
|
+
communications.push({
|
|
1958
|
+
subscriptionTypeId: id,
|
|
1959
|
+
text: String(box.label || box.text || "").trim() || "I agree to receive communications."
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
const consentToProcessText = legal?.consentToProcessText?.trim();
|
|
1963
|
+
return {
|
|
1964
|
+
names: new Set(formFieldNames(raw)),
|
|
1965
|
+
required: new Set(formRequiredNames(raw)),
|
|
1966
|
+
hasLegalConsent,
|
|
1967
|
+
captcha: raw.configuration?.captchaEnabled === true,
|
|
1968
|
+
...consentToProcessText ? { consentToProcessText } : {},
|
|
1969
|
+
communications
|
|
1970
|
+
};
|
|
1971
|
+
}
|
|
1972
|
+
function canRetryEmailOnly(required) {
|
|
1973
|
+
const names = [...required ?? []];
|
|
1974
|
+
return names.length === 0 || names.every((name) => name === "email");
|
|
1975
|
+
}
|
|
1976
|
+
function buildLegalConsent(shape, given, fallbackText) {
|
|
1977
|
+
if (!given) return void 0;
|
|
1978
|
+
if (shape && !shape.hasLegalConsent) return void 0;
|
|
1979
|
+
const consent = {
|
|
1980
|
+
consentToProcess: true,
|
|
1981
|
+
text: shape?.consentToProcessText?.trim() || fallbackText?.trim() || DEFAULT_CONSENT_TEXT
|
|
1982
|
+
};
|
|
1983
|
+
if (shape?.communications.length) {
|
|
1984
|
+
consent.communications = shape.communications.map((item) => ({
|
|
1985
|
+
value: true,
|
|
1986
|
+
subscriptionTypeId: item.subscriptionTypeId,
|
|
1987
|
+
text: item.text
|
|
1988
|
+
}));
|
|
1989
|
+
}
|
|
1990
|
+
return { consent };
|
|
1991
|
+
}
|
|
1939
1992
|
const shapeCache = /* @__PURE__ */ new Map();
|
|
1940
1993
|
function clearFormShapeCache(formGuid) {
|
|
1941
1994
|
if (formGuid) shapeCache.delete(formGuid);
|
|
@@ -1944,16 +1997,13 @@ function clearFormShapeCache(formGuid) {
|
|
|
1944
1997
|
async function loadFormShape(apiKey, formGuid) {
|
|
1945
1998
|
const cached = shapeCache.get(formGuid);
|
|
1946
1999
|
if (cached && Date.now() - cached.at < SHAPE_TTL_MS) {
|
|
1947
|
-
return
|
|
2000
|
+
return cached.shape;
|
|
1948
2001
|
}
|
|
1949
2002
|
try {
|
|
1950
2003
|
const raw = await fetchHubspotForm(apiKey, formGuid);
|
|
1951
|
-
const
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
);
|
|
1955
|
-
shapeCache.set(formGuid, { at: Date.now(), names, hasLegalConsent });
|
|
1956
|
-
return { names, hasLegalConsent };
|
|
2004
|
+
const shape = parseFormShape(raw);
|
|
2005
|
+
shapeCache.set(formGuid, { at: Date.now(), shape });
|
|
2006
|
+
return shape;
|
|
1957
2007
|
} catch {
|
|
1958
2008
|
return null;
|
|
1959
2009
|
}
|
|
@@ -2011,28 +2061,45 @@ async function submitMarketingForm(input) {
|
|
|
2011
2061
|
if (!portalId || !isFormGuid(formGuid) || !input.fields.length) {
|
|
2012
2062
|
return { ok: false, status: 0, error: "Missing portal, form GUID or fields" };
|
|
2013
2063
|
}
|
|
2064
|
+
if (input.shape?.captcha) {
|
|
2065
|
+
return {
|
|
2066
|
+
ok: false,
|
|
2067
|
+
status: 0,
|
|
2068
|
+
error: "HubSpot form has CAPTCHA enabled — the Forms API cannot submit it. Turn CAPTCHA off on that marketing form."
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2014
2071
|
const url = formsSubmitUrl(portalId, formGuid, input.region);
|
|
2015
2072
|
const context = contextPayload(input.context);
|
|
2073
|
+
const fields = input.fields.map((field) => ({
|
|
2074
|
+
objectTypeId: field.objectTypeId || "0-1",
|
|
2075
|
+
name: field.name,
|
|
2076
|
+
value: field.value
|
|
2077
|
+
}));
|
|
2016
2078
|
const base = {
|
|
2017
|
-
fields
|
|
2079
|
+
fields,
|
|
2018
2080
|
...Object.keys(context).length ? { context } : {}
|
|
2019
2081
|
};
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
} : base;
|
|
2082
|
+
const legal = buildLegalConsent(
|
|
2083
|
+
input.shape,
|
|
2084
|
+
input.consent?.given === true,
|
|
2085
|
+
input.consent?.text
|
|
2086
|
+
);
|
|
2087
|
+
const withConsent = legal ? { ...base, legalConsentOptions: legal } : base;
|
|
2029
2088
|
let result = await postForm(url, input.apiKey, withConsent);
|
|
2030
|
-
|
|
2089
|
+
const mustKeepConsent = Boolean(input.shape?.hasLegalConsent && legal);
|
|
2090
|
+
if (!result.ok && result.status === 400 && withConsent !== base && !mustKeepConsent) {
|
|
2031
2091
|
result = await postForm(url, input.apiKey, base);
|
|
2032
2092
|
}
|
|
2033
|
-
if (!result.ok && result.status === 400 && input.fields.length > 1) {
|
|
2034
|
-
const email =
|
|
2035
|
-
if (email)
|
|
2093
|
+
if (!result.ok && result.status === 400 && input.fields.length > 1 && canRetryEmailOnly(input.shape?.required)) {
|
|
2094
|
+
const email = fields.find((f) => f.name === "email");
|
|
2095
|
+
if (email) {
|
|
2096
|
+
const slim = { ...base, fields: [email] };
|
|
2097
|
+
result = await postForm(
|
|
2098
|
+
url,
|
|
2099
|
+
input.apiKey,
|
|
2100
|
+
legal && mustKeepConsent ? { ...slim, legalConsentOptions: legal } : slim
|
|
2101
|
+
);
|
|
2102
|
+
}
|
|
2036
2103
|
}
|
|
2037
2104
|
return result;
|
|
2038
2105
|
}
|
|
@@ -2414,6 +2481,7 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2414
2481
|
}
|
|
2415
2482
|
let usedFormsApi = false;
|
|
2416
2483
|
let sentFieldNames = [];
|
|
2484
|
+
let conversionError;
|
|
2417
2485
|
if (email && apiKey) {
|
|
2418
2486
|
const groups = groupByObject(form.definition, resolution.values);
|
|
2419
2487
|
for (const [object, props] of Object.entries(companyGroups)) {
|
|
@@ -2453,7 +2521,7 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2453
2521
|
ipAddress: sanitizeIp(meta.ipAddress)
|
|
2454
2522
|
},
|
|
2455
2523
|
consent: { given: meta.consent === true },
|
|
2456
|
-
|
|
2524
|
+
shape
|
|
2457
2525
|
});
|
|
2458
2526
|
if (submitted.ok) {
|
|
2459
2527
|
hubspotSynced = true;
|
|
@@ -2466,10 +2534,12 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2466
2534
|
);
|
|
2467
2535
|
}
|
|
2468
2536
|
} else {
|
|
2537
|
+
conversionError = submitted.error;
|
|
2469
2538
|
strapi.log.warn(`[hubspot] Forms API submit failed — ${submitted.error}`);
|
|
2470
2539
|
}
|
|
2471
2540
|
} catch (err) {
|
|
2472
|
-
|
|
2541
|
+
conversionError = err.message;
|
|
2542
|
+
strapi.log.warn(`[hubspot] Forms API submit failed — ${conversionError}`);
|
|
2473
2543
|
}
|
|
2474
2544
|
}
|
|
2475
2545
|
if (!usedFormsApi) {
|
|
@@ -2551,7 +2621,11 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2551
2621
|
formTitle: form.title || form.name,
|
|
2552
2622
|
email,
|
|
2553
2623
|
values: resolution.values,
|
|
2554
|
-
meta
|
|
2624
|
+
meta: {
|
|
2625
|
+
...meta,
|
|
2626
|
+
hubspotConversion: usedFormsApi,
|
|
2627
|
+
...conversionError ? { hubspotError: conversionError } : {}
|
|
2628
|
+
},
|
|
2555
2629
|
locale: form.locale ?? null,
|
|
2556
2630
|
hubspotSynced,
|
|
2557
2631
|
contactId,
|
|
@@ -2738,7 +2812,7 @@ function createFormsAdminController(strapi) {
|
|
|
2738
2812
|
locale: ctx.query.locale,
|
|
2739
2813
|
status: "published"
|
|
2740
2814
|
});
|
|
2741
|
-
ctx.body = { form: entry, published: Boolean(published) };
|
|
2815
|
+
ctx.body = { form: entry, published: Boolean(published), publishedHubspotFormId: published?.hubspotFormId ?? null };
|
|
2742
2816
|
},
|
|
2743
2817
|
async create(ctx) {
|
|
2744
2818
|
const body = ctx.request.body ?? {};
|
package/dist/server/index.mjs
CHANGED
|
@@ -1935,6 +1935,59 @@ function formFieldNames(raw) {
|
|
|
1935
1935
|
}
|
|
1936
1936
|
return names;
|
|
1937
1937
|
}
|
|
1938
|
+
function formRequiredNames(raw) {
|
|
1939
|
+
const names = [];
|
|
1940
|
+
for (const group of raw.fieldGroups ?? []) {
|
|
1941
|
+
for (const field of group.fields ?? []) {
|
|
1942
|
+
if (field.name && field.required) names.push(field.name);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
return names;
|
|
1946
|
+
}
|
|
1947
|
+
function parseFormShape(raw) {
|
|
1948
|
+
const legal = raw.legalConsentOptions;
|
|
1949
|
+
const hasLegalConsent = Boolean(
|
|
1950
|
+
legal && typeof legal === "object" && legal.type && legal.type !== "none"
|
|
1951
|
+
);
|
|
1952
|
+
const communications = [];
|
|
1953
|
+
for (const box of legal?.communicationsCheckboxes ?? []) {
|
|
1954
|
+
const id = Number(box.subscriptionTypeId ?? box.communicationTypeId);
|
|
1955
|
+
if (!Number.isFinite(id) || id <= 0) continue;
|
|
1956
|
+
communications.push({
|
|
1957
|
+
subscriptionTypeId: id,
|
|
1958
|
+
text: String(box.label || box.text || "").trim() || "I agree to receive communications."
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
const consentToProcessText = legal?.consentToProcessText?.trim();
|
|
1962
|
+
return {
|
|
1963
|
+
names: new Set(formFieldNames(raw)),
|
|
1964
|
+
required: new Set(formRequiredNames(raw)),
|
|
1965
|
+
hasLegalConsent,
|
|
1966
|
+
captcha: raw.configuration?.captchaEnabled === true,
|
|
1967
|
+
...consentToProcessText ? { consentToProcessText } : {},
|
|
1968
|
+
communications
|
|
1969
|
+
};
|
|
1970
|
+
}
|
|
1971
|
+
function canRetryEmailOnly(required) {
|
|
1972
|
+
const names = [...required ?? []];
|
|
1973
|
+
return names.length === 0 || names.every((name) => name === "email");
|
|
1974
|
+
}
|
|
1975
|
+
function buildLegalConsent(shape, given, fallbackText) {
|
|
1976
|
+
if (!given) return void 0;
|
|
1977
|
+
if (shape && !shape.hasLegalConsent) return void 0;
|
|
1978
|
+
const consent = {
|
|
1979
|
+
consentToProcess: true,
|
|
1980
|
+
text: shape?.consentToProcessText?.trim() || fallbackText?.trim() || DEFAULT_CONSENT_TEXT
|
|
1981
|
+
};
|
|
1982
|
+
if (shape?.communications.length) {
|
|
1983
|
+
consent.communications = shape.communications.map((item) => ({
|
|
1984
|
+
value: true,
|
|
1985
|
+
subscriptionTypeId: item.subscriptionTypeId,
|
|
1986
|
+
text: item.text
|
|
1987
|
+
}));
|
|
1988
|
+
}
|
|
1989
|
+
return { consent };
|
|
1990
|
+
}
|
|
1938
1991
|
const shapeCache = /* @__PURE__ */ new Map();
|
|
1939
1992
|
function clearFormShapeCache(formGuid) {
|
|
1940
1993
|
if (formGuid) shapeCache.delete(formGuid);
|
|
@@ -1943,16 +1996,13 @@ function clearFormShapeCache(formGuid) {
|
|
|
1943
1996
|
async function loadFormShape(apiKey, formGuid) {
|
|
1944
1997
|
const cached = shapeCache.get(formGuid);
|
|
1945
1998
|
if (cached && Date.now() - cached.at < SHAPE_TTL_MS) {
|
|
1946
|
-
return
|
|
1999
|
+
return cached.shape;
|
|
1947
2000
|
}
|
|
1948
2001
|
try {
|
|
1949
2002
|
const raw = await fetchHubspotForm(apiKey, formGuid);
|
|
1950
|
-
const
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
);
|
|
1954
|
-
shapeCache.set(formGuid, { at: Date.now(), names, hasLegalConsent });
|
|
1955
|
-
return { names, hasLegalConsent };
|
|
2003
|
+
const shape = parseFormShape(raw);
|
|
2004
|
+
shapeCache.set(formGuid, { at: Date.now(), shape });
|
|
2005
|
+
return shape;
|
|
1956
2006
|
} catch {
|
|
1957
2007
|
return null;
|
|
1958
2008
|
}
|
|
@@ -2010,28 +2060,45 @@ async function submitMarketingForm(input) {
|
|
|
2010
2060
|
if (!portalId || !isFormGuid(formGuid) || !input.fields.length) {
|
|
2011
2061
|
return { ok: false, status: 0, error: "Missing portal, form GUID or fields" };
|
|
2012
2062
|
}
|
|
2063
|
+
if (input.shape?.captcha) {
|
|
2064
|
+
return {
|
|
2065
|
+
ok: false,
|
|
2066
|
+
status: 0,
|
|
2067
|
+
error: "HubSpot form has CAPTCHA enabled — the Forms API cannot submit it. Turn CAPTCHA off on that marketing form."
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2013
2070
|
const url = formsSubmitUrl(portalId, formGuid, input.region);
|
|
2014
2071
|
const context = contextPayload(input.context);
|
|
2072
|
+
const fields = input.fields.map((field) => ({
|
|
2073
|
+
objectTypeId: field.objectTypeId || "0-1",
|
|
2074
|
+
name: field.name,
|
|
2075
|
+
value: field.value
|
|
2076
|
+
}));
|
|
2015
2077
|
const base = {
|
|
2016
|
-
fields
|
|
2078
|
+
fields,
|
|
2017
2079
|
...Object.keys(context).length ? { context } : {}
|
|
2018
2080
|
};
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
} : base;
|
|
2081
|
+
const legal = buildLegalConsent(
|
|
2082
|
+
input.shape,
|
|
2083
|
+
input.consent?.given === true,
|
|
2084
|
+
input.consent?.text
|
|
2085
|
+
);
|
|
2086
|
+
const withConsent = legal ? { ...base, legalConsentOptions: legal } : base;
|
|
2028
2087
|
let result = await postForm(url, input.apiKey, withConsent);
|
|
2029
|
-
|
|
2088
|
+
const mustKeepConsent = Boolean(input.shape?.hasLegalConsent && legal);
|
|
2089
|
+
if (!result.ok && result.status === 400 && withConsent !== base && !mustKeepConsent) {
|
|
2030
2090
|
result = await postForm(url, input.apiKey, base);
|
|
2031
2091
|
}
|
|
2032
|
-
if (!result.ok && result.status === 400 && input.fields.length > 1) {
|
|
2033
|
-
const email =
|
|
2034
|
-
if (email)
|
|
2092
|
+
if (!result.ok && result.status === 400 && input.fields.length > 1 && canRetryEmailOnly(input.shape?.required)) {
|
|
2093
|
+
const email = fields.find((f) => f.name === "email");
|
|
2094
|
+
if (email) {
|
|
2095
|
+
const slim = { ...base, fields: [email] };
|
|
2096
|
+
result = await postForm(
|
|
2097
|
+
url,
|
|
2098
|
+
input.apiKey,
|
|
2099
|
+
legal && mustKeepConsent ? { ...slim, legalConsentOptions: legal } : slim
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2035
2102
|
}
|
|
2036
2103
|
return result;
|
|
2037
2104
|
}
|
|
@@ -2413,6 +2480,7 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2413
2480
|
}
|
|
2414
2481
|
let usedFormsApi = false;
|
|
2415
2482
|
let sentFieldNames = [];
|
|
2483
|
+
let conversionError;
|
|
2416
2484
|
if (email && apiKey) {
|
|
2417
2485
|
const groups = groupByObject(form.definition, resolution.values);
|
|
2418
2486
|
for (const [object, props] of Object.entries(companyGroups)) {
|
|
@@ -2452,7 +2520,7 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2452
2520
|
ipAddress: sanitizeIp(meta.ipAddress)
|
|
2453
2521
|
},
|
|
2454
2522
|
consent: { given: meta.consent === true },
|
|
2455
|
-
|
|
2523
|
+
shape
|
|
2456
2524
|
});
|
|
2457
2525
|
if (submitted.ok) {
|
|
2458
2526
|
hubspotSynced = true;
|
|
@@ -2465,10 +2533,12 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2465
2533
|
);
|
|
2466
2534
|
}
|
|
2467
2535
|
} else {
|
|
2536
|
+
conversionError = submitted.error;
|
|
2468
2537
|
strapi.log.warn(`[hubspot] Forms API submit failed — ${submitted.error}`);
|
|
2469
2538
|
}
|
|
2470
2539
|
} catch (err) {
|
|
2471
|
-
|
|
2540
|
+
conversionError = err.message;
|
|
2541
|
+
strapi.log.warn(`[hubspot] Forms API submit failed — ${conversionError}`);
|
|
2472
2542
|
}
|
|
2473
2543
|
}
|
|
2474
2544
|
if (!usedFormsApi) {
|
|
@@ -2550,7 +2620,11 @@ function createFormsService(strapi, _opts = {}) {
|
|
|
2550
2620
|
formTitle: form.title || form.name,
|
|
2551
2621
|
email,
|
|
2552
2622
|
values: resolution.values,
|
|
2553
|
-
meta
|
|
2623
|
+
meta: {
|
|
2624
|
+
...meta,
|
|
2625
|
+
hubspotConversion: usedFormsApi,
|
|
2626
|
+
...conversionError ? { hubspotError: conversionError } : {}
|
|
2627
|
+
},
|
|
2554
2628
|
locale: form.locale ?? null,
|
|
2555
2629
|
hubspotSynced,
|
|
2556
2630
|
contactId,
|
|
@@ -2737,7 +2811,7 @@ function createFormsAdminController(strapi) {
|
|
|
2737
2811
|
locale: ctx.query.locale,
|
|
2738
2812
|
status: "published"
|
|
2739
2813
|
});
|
|
2740
|
-
ctx.body = { form: entry, published: Boolean(published) };
|
|
2814
|
+
ctx.body = { form: entry, published: Boolean(published), publishedHubspotFormId: published?.hubspotFormId ?? null };
|
|
2741
2815
|
},
|
|
2742
2816
|
async create(ctx) {
|
|
2743
2817
|
const body = ctx.request.body ?? {};
|
|
@@ -34,9 +34,54 @@ export declare function formFieldNames(raw: {
|
|
|
34
34
|
fieldGroups?: {
|
|
35
35
|
fields?: {
|
|
36
36
|
name?: string;
|
|
37
|
+
required?: boolean;
|
|
37
38
|
}[];
|
|
38
39
|
}[];
|
|
39
40
|
}): string[];
|
|
41
|
+
export declare function formRequiredNames(raw: {
|
|
42
|
+
fieldGroups?: {
|
|
43
|
+
fields?: {
|
|
44
|
+
name?: string;
|
|
45
|
+
required?: boolean;
|
|
46
|
+
}[];
|
|
47
|
+
}[];
|
|
48
|
+
}): string[];
|
|
49
|
+
export interface CommunicationConsent {
|
|
50
|
+
subscriptionTypeId: number;
|
|
51
|
+
text: string;
|
|
52
|
+
}
|
|
53
|
+
export interface FormShape {
|
|
54
|
+
names: Set<string>;
|
|
55
|
+
required: Set<string>;
|
|
56
|
+
hasLegalConsent: boolean;
|
|
57
|
+
captcha: boolean;
|
|
58
|
+
consentToProcessText?: string;
|
|
59
|
+
communications: CommunicationConsent[];
|
|
60
|
+
}
|
|
61
|
+
export declare function parseFormShape(raw: {
|
|
62
|
+
fieldGroups?: {
|
|
63
|
+
fields?: {
|
|
64
|
+
name?: string;
|
|
65
|
+
required?: boolean;
|
|
66
|
+
}[];
|
|
67
|
+
}[];
|
|
68
|
+
configuration?: {
|
|
69
|
+
captchaEnabled?: boolean;
|
|
70
|
+
};
|
|
71
|
+
legalConsentOptions?: {
|
|
72
|
+
type?: string;
|
|
73
|
+
consentToProcessText?: string;
|
|
74
|
+
communicationsCheckboxes?: {
|
|
75
|
+
label?: string;
|
|
76
|
+
text?: string;
|
|
77
|
+
subscriptionTypeId?: number | string;
|
|
78
|
+
communicationTypeId?: number | string;
|
|
79
|
+
}[];
|
|
80
|
+
} | null;
|
|
81
|
+
}): FormShape;
|
|
82
|
+
/** Email-only retry is only safe when HubSpot doesn't require other fields. */
|
|
83
|
+
export declare function canRetryEmailOnly(required: Iterable<string> | undefined): boolean;
|
|
84
|
+
export declare function buildLegalConsent(shape: Pick<FormShape, "hasLegalConsent" | "communications" | "consentToProcessText"> | null | undefined, given: boolean, fallbackText?: string): Record<string, unknown> | undefined;
|
|
40
85
|
export interface FormSubmitContext {
|
|
41
86
|
hutk?: string;
|
|
42
87
|
pageUri?: string;
|
|
@@ -51,24 +96,25 @@ export interface FormSubmitInput {
|
|
|
51
96
|
fields: {
|
|
52
97
|
name: string;
|
|
53
98
|
value: string;
|
|
99
|
+
objectTypeId?: string;
|
|
54
100
|
}[];
|
|
55
101
|
context?: FormSubmitContext;
|
|
56
102
|
consent?: {
|
|
57
103
|
given: boolean;
|
|
58
104
|
text?: string;
|
|
59
105
|
};
|
|
60
|
-
|
|
106
|
+
shape?: FormShape | null;
|
|
61
107
|
}
|
|
62
108
|
export declare function clearFormShapeCache(formGuid?: string): void;
|
|
63
|
-
export declare function loadFormShape(apiKey: string, formGuid: string): Promise<
|
|
64
|
-
names: Set<string>;
|
|
65
|
-
hasLegalConsent: boolean;
|
|
66
|
-
} | null>;
|
|
109
|
+
export declare function loadFormShape(apiKey: string, formGuid: string): Promise<FormShape | null>;
|
|
67
110
|
export declare function findContactIdByEmail(apiKey: string, email: string): Promise<string | undefined>;
|
|
68
111
|
/**
|
|
69
112
|
* Submit a marketing form. Extra fields HubSpot doesn't know on that form
|
|
70
|
-
* 400 the whole request, so callers should filter first
|
|
71
|
-
*
|
|
113
|
+
* 400 the whole request, so callers should filter first. A GDPR block on the
|
|
114
|
+
* HubSpot form needs the matching legalConsentOptions (including
|
|
115
|
+
* communications); stripping consent to "retry" would 400 forever. Email-only
|
|
116
|
+
* retry is only used when HubSpot doesn't require other fields. CAPTCHA
|
|
117
|
+
* cannot be solved server-side.
|
|
72
118
|
*/
|
|
73
119
|
export declare function submitMarketingForm(input: FormSubmitInput): Promise<{
|
|
74
120
|
ok: boolean;
|
|
@@ -73,9 +73,18 @@ export interface RawHubspotForm {
|
|
|
73
73
|
type?: string;
|
|
74
74
|
value?: string;
|
|
75
75
|
};
|
|
76
|
+
captchaEnabled?: boolean;
|
|
76
77
|
};
|
|
77
78
|
legalConsentOptions?: {
|
|
78
79
|
type?: string;
|
|
80
|
+
consentToProcessText?: string;
|
|
81
|
+
communicationsCheckboxes?: {
|
|
82
|
+
required?: boolean;
|
|
83
|
+
label?: string;
|
|
84
|
+
text?: string;
|
|
85
|
+
subscriptionTypeId?: number | string;
|
|
86
|
+
communicationTypeId?: number | string;
|
|
87
|
+
}[];
|
|
79
88
|
} | null;
|
|
80
89
|
}
|
|
81
90
|
export declare function convertHubspotForm(raw: RawHubspotForm): ConvertedHubspotForm;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-hubspot",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.5",
|
|
4
4
|
"description": "The form builder for HubSpot in Strapi — multi-step forms with conditional fields mapped to real CRM properties, a public submit pipeline with retries, and save-time mapping validation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|