strapi-plugin-hubspot 0.16.2 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +8 -5
  3. package/dist/_chunks/{Forms-BOQWely0.mjs → Forms-BBaw53Tz.mjs} +3 -3
  4. package/dist/_chunks/{Forms-mMNP7hc9.js → Forms-CIJrUB_n.js} +3 -3
  5. package/dist/_chunks/{HubspotFormInput-DCkoavrN.mjs → HubspotFormInput-DIo6hCNz.mjs} +1 -1
  6. package/dist/_chunks/{HubspotFormInput-DI35Aqiu.js → HubspotFormInput-DSTuQ_bx.js} +1 -1
  7. package/dist/_chunks/{HubspotObjectInput-BbnvhdbD.mjs → HubspotObjectInput-BA16dswz.mjs} +3 -3
  8. package/dist/_chunks/{HubspotObjectInput-Cq1TuL_l.js → HubspotObjectInput-BIqC8tl2.js} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-BLZzsW08.js → HubspotPropertyInput-C77Op1Wm.js} +3 -3
  10. package/dist/_chunks/{HubspotPropertyInput-BHfpBD36.mjs → HubspotPropertyInput-Dsn7ikop.mjs} +3 -3
  11. package/dist/_chunks/{Settings-DqRpHtnT.mjs → Settings-DxX9Uh_2.mjs} +21 -3
  12. package/dist/_chunks/{Settings-BAsx0LGv.js → Settings-PVhJVPqq.js} +21 -3
  13. package/dist/_chunks/{index-CLAy5dVN.mjs → index-B8GYi6sw.mjs} +5 -5
  14. package/dist/_chunks/{index-R3ReZXF1.js → index-XEuSPuUj.js} +5 -5
  15. package/dist/_chunks/{objectLabels--zOmqsfm.mjs → objectLabels-DybqhBdT.mjs} +1 -1
  16. package/dist/_chunks/{objectLabels-CW2iBOkD.js → objectLabels-wBwfLdZt.js} +1 -1
  17. package/dist/_chunks/{useHubspotSchema-Bz2o1BU-.mjs → useHubspotSchema-DtcHHUOb.mjs} +1 -1
  18. package/dist/_chunks/{useHubspotSchema-BRzzvs9t.js → useHubspotSchema-WvgW3od8.js} +1 -1
  19. package/dist/admin/index.js +1 -1
  20. package/dist/admin/index.mjs +1 -1
  21. package/dist/server/index.js +9 -5
  22. package/dist/server/index.mjs +9 -5
  23. package/dist/server/src/forms.d.ts +3 -2
  24. package/dist/server/src/index.d.ts +1 -0
  25. package/dist/server/src/settings.d.ts +6 -0
  26. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.16.3 — 2026-09-22
6
+
7
+ ### Changed
8
+ - Timeline recap notes (`forms.timelineNote`, default `true`) now also write
9
+ after a native Forms API conversion: page URL and originating subject sit
10
+ on the contact next to the conversion. The Forms API already forwards
11
+ `context.pageUri` / `pageName`. Toggle lives in Settings → HubSpot.
12
+
5
13
  ## 0.16.2 — 2026-09-22
6
14
 
7
15
  ### Added
package/README.md CHANGED
@@ -54,11 +54,14 @@ upserts can share the same plugin:
54
54
  | `forms.submissionMode` | `auto` | `auto`: Forms API when a marketing GUID is linked, else CRM upsert. `forms`: always try the Forms API. `crm`: never count as a conversion |
55
55
  | `forms.writeExtraProperties` | `true` | After a conversion, CRM-write mapped contact fields the HubSpot form dropped (they 400 the Forms API) |
56
56
  | `forms.syncFieldsOnPublish` | `false` | On publish, PATCH missing mapped **contact** fields onto the HubSpot form. Off by default so HubSpot-first installs aren't mutated |
57
+ | `forms.timelineNote` | `true` | Recap note on the contact after a successful sync (page URL, subject, answers). Sits next to a native conversion; turn off if you only want the form submission |
57
58
 
58
- The visitor's `hutk` is forwarded so attribution sticks. Then the contact is
59
- looked up by email and, when the address is on a corporate domain, the company
60
- is found-or-created and associated. Timeline notes are opt-in and only used
61
- on the CRM-upsert path.
59
+ The visitor's `hutk` is forwarded so attribution sticks. The conversion carries
60
+ `context.pageUri` / `pageName` (the page the visitor submitted from). Then the
61
+ contact is looked up by email and, when the address is on a corporate domain,
62
+ the company is found-or-created and associated. Timeline notes (`forms.timelineNote`,
63
+ default `true`) add a recap of that page plus the originating subject on the
64
+ contact timeline — they don't replace the conversion.
62
65
 
63
66
  CRM properties are **never created**. Map to properties that already exist in
64
67
  the portal; opting into field sync only adds form fields that point at those
@@ -75,7 +78,7 @@ hubspot: {
75
78
  region: env("HUBSPOT_REGION", "eu1"), // eu1 → api-eu1.hsforms.com
76
79
  forms: {
77
80
  companyFromDomain: true, // Company by corporate domain + association
78
- timelineNote: false, // recap note on the CRM-upsert fallback only
81
+ timelineNote: true, // recap note (page + subject) next to the conversion
79
82
  defaultFormId: env("HUBSPOT_DEFAULT_FORM_ID", ""),
80
83
  submissionMode: "auto", // auto | forms | crm
81
84
  writeExtraProperties: true,
@@ -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-CLAy5dVN.mjs";
8
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-B8GYi6sw.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--zOmqsfm.mjs";
13
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
12
+ import { o as objectLabel } from "./objectLabels-DybqhBdT.mjs";
13
+ import { u as useHubspotSchema } from "./useHubspotSchema-DtcHHUOb.mjs";
14
14
  const OPERATORS = [
15
15
  "eq",
16
16
  "neq",
@@ -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-R3ReZXF1.js");
10
+ const index$1 = require("./index-XEuSPuUj.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-CW2iBOkD.js");
15
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
14
+ const objectLabels = require("./objectLabels-wBwfLdZt.js");
15
+ const useHubspotSchema = require("./useHubspotSchema-WvgW3od8.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" } });
@@ -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-CLAy5dVN.mjs";
6
+ import { P as PLUGIN_ID, g as getTranslation } from "./index-B8GYi6sw.mjs";
7
7
  const HubspotFormInput = React.forwardRef(
8
8
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
9
9
  const { formatMessage } = useIntl();
@@ -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-R3ReZXF1.js");
8
+ const index$1 = require("./index-XEuSPuUj.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" } });
@@ -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-CLAy5dVN.mjs";
6
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
7
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
5
+ import { g as getTranslation } from "./index-B8GYi6sw.mjs";
6
+ import { o as objectLabel } from "./objectLabels-DybqhBdT.mjs";
7
+ import { u as useHubspotSchema } from "./useHubspotSchema-DtcHHUOb.mjs";
8
8
  const HubspotObjectInput = React.forwardRef(
9
9
  ({ name, value, onChange, disabled, error, required, label, hint, labelAction }, ref) => {
10
10
  const intl = 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-R3ReZXF1.js");
8
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
9
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
7
+ const index$1 = require("./index-XEuSPuUj.js");
8
+ const objectLabels = require("./objectLabels-wBwfLdZt.js");
9
+ const useHubspotSchema = require("./useHubspotSchema-WvgW3od8.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" } });
@@ -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-R3ReZXF1.js");
10
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
11
- const useHubspotSchema = require("./useHubspotSchema-BRzzvs9t.js");
9
+ const index$1 = require("./index-XEuSPuUj.js");
10
+ const objectLabels = require("./objectLabels-wBwfLdZt.js");
11
+ const useHubspotSchema = require("./useHubspotSchema-WvgW3od8.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" } });
@@ -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-CLAy5dVN.mjs";
8
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
9
- import { u as useHubspotSchema } from "./useHubspotSchema-Bz2o1BU-.mjs";
7
+ import { g as getTranslation } from "./index-B8GYi6sw.mjs";
8
+ import { o as objectLabel } from "./objectLabels-DybqhBdT.mjs";
9
+ import { u as useHubspotSchema } from "./useHubspotSchema-DtcHHUOb.mjs";
10
10
  const oneLine = {
11
11
  display: "block",
12
12
  whiteSpace: "nowrap",
@@ -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-CLAy5dVN.mjs";
6
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-B8GYi6sw.mjs";
7
7
  import { Link as Link$1 } from "react-router-dom";
8
- import { o as objectLabel } from "./objectLabels--zOmqsfm.mjs";
8
+ import { o as objectLabel } from "./objectLabels-DybqhBdT.mjs";
9
9
  const AuditSection = ({ configured }) => {
10
10
  const intl = useIntl();
11
11
  const { formatMessage } = intl;
@@ -184,6 +184,7 @@ const HubspotSettings = () => {
184
184
  const [submissionMode, setSubmissionMode] = React.useState("auto");
185
185
  const [writeExtraProperties, setWriteExtraProperties] = React.useState(true);
186
186
  const [syncFieldsOnPublish, setSyncFieldsOnPublish] = React.useState(false);
187
+ const [timelineNote, setTimelineNote] = React.useState(true);
187
188
  const [forms, setForms] = React.useState([]);
188
189
  const [busy, setBusy] = React.useState(false);
189
190
  const [feedback, setFeedback] = React.useState(
@@ -198,6 +199,7 @@ const HubspotSettings = () => {
198
199
  setSubmissionMode(data.submissionMode === "crm" || data.submissionMode === "forms" ? data.submissionMode : "auto");
199
200
  setWriteExtraProperties(data.writeExtraProperties !== false);
200
201
  setSyncFieldsOnPublish(data.syncFieldsOnPublish === true);
202
+ setTimelineNote(data.timelineNote !== false);
201
203
  setForms(Array.isArray(data.forms) ? data.forms : []);
202
204
  };
203
205
  const load = React.useCallback(async () => {
@@ -220,7 +222,8 @@ const HubspotSettings = () => {
220
222
  defaultFormId,
221
223
  submissionMode,
222
224
  writeExtraProperties,
223
- syncFieldsOnPublish
225
+ syncFieldsOnPublish,
226
+ timelineNote
224
227
  });
225
228
  setApiKey("");
226
229
  await load();
@@ -454,6 +457,21 @@ const HubspotSettings = () => {
454
457
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
455
458
  "settings.sync.hint",
456
459
  "Strapi-first installs: a field added here appears on the HubSpot form next publish. HubSpot-first installs should leave this off — importing a form already carries its fields. Properties themselves are never created; map to ones that exist in the portal."
460
+ ) }),
461
+ /* @__PURE__ */ jsx(
462
+ Checkbox,
463
+ {
464
+ checked: timelineNote,
465
+ onCheckedChange: (checked) => setTimelineNote(checked === true),
466
+ children: t(
467
+ "settings.note.label",
468
+ "Also write a recap note on the contact (page, subject, answers)"
469
+ )
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
473
+ "settings.note.hint",
474
+ "The conversion already carries the page URL (pageUri). The note puts that page plus the originating subject on the contact timeline, next to the native form submission."
457
475
  ) })
458
476
  ] }) }),
459
477
  /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
@@ -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-R3ReZXF1.js");
8
+ const index$1 = require("./index-XEuSPuUj.js");
9
9
  const reactRouterDom = require("react-router-dom");
10
- const objectLabels = require("./objectLabels-CW2iBOkD.js");
10
+ const objectLabels = require("./objectLabels-wBwfLdZt.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" } });
@@ -204,6 +204,7 @@ const HubspotSettings = () => {
204
204
  const [submissionMode, setSubmissionMode] = React__namespace.useState("auto");
205
205
  const [writeExtraProperties, setWriteExtraProperties] = React__namespace.useState(true);
206
206
  const [syncFieldsOnPublish, setSyncFieldsOnPublish] = React__namespace.useState(false);
207
+ const [timelineNote, setTimelineNote] = React__namespace.useState(true);
207
208
  const [forms, setForms] = React__namespace.useState([]);
208
209
  const [busy, setBusy] = React__namespace.useState(false);
209
210
  const [feedback, setFeedback] = React__namespace.useState(
@@ -218,6 +219,7 @@ const HubspotSettings = () => {
218
219
  setSubmissionMode(data.submissionMode === "crm" || data.submissionMode === "forms" ? data.submissionMode : "auto");
219
220
  setWriteExtraProperties(data.writeExtraProperties !== false);
220
221
  setSyncFieldsOnPublish(data.syncFieldsOnPublish === true);
222
+ setTimelineNote(data.timelineNote !== false);
221
223
  setForms(Array.isArray(data.forms) ? data.forms : []);
222
224
  };
223
225
  const load = React__namespace.useCallback(async () => {
@@ -240,7 +242,8 @@ const HubspotSettings = () => {
240
242
  defaultFormId,
241
243
  submissionMode,
242
244
  writeExtraProperties,
243
- syncFieldsOnPublish
245
+ syncFieldsOnPublish,
246
+ timelineNote
244
247
  });
245
248
  setApiKey("");
246
249
  await load();
@@ -474,6 +477,21 @@ const HubspotSettings = () => {
474
477
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
475
478
  "settings.sync.hint",
476
479
  "Strapi-first installs: a field added here appears on the HubSpot form next publish. HubSpot-first installs should leave this off — importing a form already carries its fields. Properties themselves are never created; map to ones that exist in the portal."
480
+ ) }),
481
+ /* @__PURE__ */ jsxRuntime.jsx(
482
+ designSystem.Checkbox,
483
+ {
484
+ checked: timelineNote,
485
+ onCheckedChange: (checked) => setTimelineNote(checked === true),
486
+ children: t(
487
+ "settings.note.label",
488
+ "Also write a recap note on the contact (page, subject, answers)"
489
+ )
490
+ }
491
+ ),
492
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
493
+ "settings.note.hint",
494
+ "The conversion already carries the page URL (pageUri). The note puts that page plus the originating subject on the contact timeline, next to the native form submission."
477
495
  ) })
478
496
  ] }) }),
479
497
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
@@ -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-BOQWely0.mjs")).default
28
+ Component: async () => (await import("./Forms-BBaw53Tz.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-BHfpBD36.mjs")
43
+ Input: async () => import("./HubspotPropertyInput-Dsn7ikop.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-BbnvhdbD.mjs")
106
+ Input: async () => import("./HubspotObjectInput-BA16dswz.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-DCkoavrN.mjs")
122
+ Input: async () => import("./HubspotFormInput-DIo6hCNz.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-DqRpHtnT.mjs")).default
138
+ Component: async () => (await import("./Settings-DxX9Uh_2.mjs")).default
139
139
  }
140
140
  ]
141
141
  );
@@ -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-mMNP7hc9.js"))).default
29
+ Component: async () => (await Promise.resolve().then(() => require("./Forms-CIJrUB_n.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-BLZzsW08.js"))
44
+ Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-C77Op1Wm.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-Cq1TuL_l.js"))
107
+ Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-BIqC8tl2.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-DI35Aqiu.js"))
123
+ Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-DSTuQ_bx.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-BAsx0LGv.js"))).default
139
+ Component: async () => (await Promise.resolve().then(() => require("./Settings-PVhJVPqq.js"))).default
140
140
  }
141
141
  ]
142
142
  );
@@ -1,4 +1,4 @@
1
- import { g as getTranslation } from "./index-CLAy5dVN.mjs";
1
+ import { g as getTranslation } from "./index-B8GYi6sw.mjs";
2
2
  const STANDARD = /* @__PURE__ */ new Set([
3
3
  "contact",
4
4
  "company",
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const index = require("./index-R3ReZXF1.js");
2
+ const index = require("./index-XEuSPuUj.js");
3
3
  const STANDARD = /* @__PURE__ */ new Set([
4
4
  "contact",
5
5
  "company",
@@ -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-CLAy5dVN.mjs";
3
+ import { P as PLUGIN_ID } from "./index-B8GYi6sw.mjs";
4
4
  let cached = null;
5
5
  let inFlight = null;
6
6
  const listeners = /* @__PURE__ */ new Set();
@@ -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-R3ReZXF1.js");
4
+ const index = require("./index-XEuSPuUj.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,4 +1,4 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-R3ReZXF1.js");
2
+ const index = require("../_chunks/index-XEuSPuUj.js");
3
3
  require("@strapi/icons");
4
4
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-CLAy5dVN.mjs";
1
+ import { i } from "../_chunks/index-B8GYi6sw.mjs";
2
2
  import "@strapi/icons";
3
3
  export {
4
4
  i as default
@@ -191,7 +191,8 @@ function policyFrom(stored, forms) {
191
191
  return {
192
192
  submissionMode: asSubmissionMode(stored.submissionMode) ?? asSubmissionMode(forms.submissionMode) ?? "auto",
193
193
  writeExtraProperties: asBool(stored.writeExtraProperties) ?? asBool(forms.writeExtraProperties) ?? true,
194
- syncFieldsOnPublish: asBool(stored.syncFieldsOnPublish) ?? asBool(forms.syncFieldsOnPublish) ?? false
194
+ syncFieldsOnPublish: asBool(stored.syncFieldsOnPublish) ?? asBool(forms.syncFieldsOnPublish) ?? false,
195
+ timelineNote: asBool(stored.timelineNote) ?? asBool(forms.timelineNote) ?? true
195
196
  };
196
197
  }
197
198
  async function resolvePolicy(strapi) {
@@ -275,6 +276,9 @@ async function patchStoredSettings(strapi, body) {
275
276
  if ("syncFieldsOnPublish" in body && typeof body.syncFieldsOnPublish === "boolean") {
276
277
  next.syncFieldsOnPublish = body.syncFieldsOnPublish;
277
278
  }
279
+ if ("timelineNote" in body && typeof body.timelineNote === "boolean") {
280
+ next.timelineNote = body.timelineNote;
281
+ }
278
282
  await setStoredSettings(strapi, next);
279
283
  }
280
284
  async function clearStoredApiKey(strapi) {
@@ -2445,7 +2449,7 @@ function createFormsService(strapi, _opts = {}) {
2445
2449
  context: {
2446
2450
  hutk: sanitizeHutk(meta.hutk),
2447
2451
  pageUri: typeof meta.pageUrl === "string" ? meta.pageUrl : void 0,
2448
- pageName: typeof meta.pageName === "string" && meta.pageName || (form.title || form.name) || void 0,
2452
+ pageName: typeof meta.pageName === "string" && meta.pageName || typeof meta.originLabel === "string" && meta.originLabel || (form.title || form.name) || void 0,
2449
2453
  ipAddress: sanitizeIp(meta.ipAddress)
2450
2454
  },
2451
2455
  consent: { given: meta.consent === true },
@@ -2525,7 +2529,7 @@ function createFormsService(strapi, _opts = {}) {
2525
2529
  strapi.log.warn(`[hubspot] company sync failed (contact OK) — ${err.message}`);
2526
2530
  }
2527
2531
  }
2528
- if (contactId && config2.timelineNote && !usedFormsApi) {
2532
+ if (contactId && policy.timelineNote) {
2529
2533
  try {
2530
2534
  await createLeadNote(apiKey, {
2531
2535
  contactId,
@@ -3334,8 +3338,8 @@ const config = {
3334
3338
  // Submission pipeline of the built forms:
3335
3339
  // - companyFromDomain: a corporate email upserts the Company (deduped by
3336
3340
  // domain) and associates it to the contact;
3337
- // - timelineNote: recap note on the CRM-upsert fallback only (off when
3338
- // submissions go through the marketing Forms API);
3341
+ // - timelineNote: recap note on the contact after a successful sync
3342
+ // (page URL, subject, answers) — alongside a Forms API conversion;
3339
3343
  // - defaultFormId: portal-wide marketing form GUID when a builder form
3340
3344
  // doesn't set its own — swap with the portal at production cutover.
3341
3345
  // - submissionMode / writeExtraProperties / syncFieldsOnPublish: see
@@ -190,7 +190,8 @@ function policyFrom(stored, forms) {
190
190
  return {
191
191
  submissionMode: asSubmissionMode(stored.submissionMode) ?? asSubmissionMode(forms.submissionMode) ?? "auto",
192
192
  writeExtraProperties: asBool(stored.writeExtraProperties) ?? asBool(forms.writeExtraProperties) ?? true,
193
- syncFieldsOnPublish: asBool(stored.syncFieldsOnPublish) ?? asBool(forms.syncFieldsOnPublish) ?? false
193
+ syncFieldsOnPublish: asBool(stored.syncFieldsOnPublish) ?? asBool(forms.syncFieldsOnPublish) ?? false,
194
+ timelineNote: asBool(stored.timelineNote) ?? asBool(forms.timelineNote) ?? true
194
195
  };
195
196
  }
196
197
  async function resolvePolicy(strapi) {
@@ -274,6 +275,9 @@ async function patchStoredSettings(strapi, body) {
274
275
  if ("syncFieldsOnPublish" in body && typeof body.syncFieldsOnPublish === "boolean") {
275
276
  next.syncFieldsOnPublish = body.syncFieldsOnPublish;
276
277
  }
278
+ if ("timelineNote" in body && typeof body.timelineNote === "boolean") {
279
+ next.timelineNote = body.timelineNote;
280
+ }
277
281
  await setStoredSettings(strapi, next);
278
282
  }
279
283
  async function clearStoredApiKey(strapi) {
@@ -2444,7 +2448,7 @@ function createFormsService(strapi, _opts = {}) {
2444
2448
  context: {
2445
2449
  hutk: sanitizeHutk(meta.hutk),
2446
2450
  pageUri: typeof meta.pageUrl === "string" ? meta.pageUrl : void 0,
2447
- pageName: typeof meta.pageName === "string" && meta.pageName || (form.title || form.name) || void 0,
2451
+ pageName: typeof meta.pageName === "string" && meta.pageName || typeof meta.originLabel === "string" && meta.originLabel || (form.title || form.name) || void 0,
2448
2452
  ipAddress: sanitizeIp(meta.ipAddress)
2449
2453
  },
2450
2454
  consent: { given: meta.consent === true },
@@ -2524,7 +2528,7 @@ function createFormsService(strapi, _opts = {}) {
2524
2528
  strapi.log.warn(`[hubspot] company sync failed (contact OK) — ${err.message}`);
2525
2529
  }
2526
2530
  }
2527
- if (contactId && config2.timelineNote && !usedFormsApi) {
2531
+ if (contactId && policy.timelineNote) {
2528
2532
  try {
2529
2533
  await createLeadNote(apiKey, {
2530
2534
  contactId,
@@ -3333,8 +3337,8 @@ const config = {
3333
3337
  // Submission pipeline of the built forms:
3334
3338
  // - companyFromDomain: a corporate email upserts the Company (deduped by
3335
3339
  // domain) and associates it to the contact;
3336
- // - timelineNote: recap note on the CRM-upsert fallback only (off when
3337
- // submissions go through the marketing Forms API);
3340
+ // - timelineNote: recap note on the contact after a successful sync
3341
+ // (page URL, subject, answers) — alongside a Forms API conversion;
3338
3342
  // - defaultFormId: portal-wide marketing form GUID when a builder form
3339
3343
  // doesn't set its own — swap with the portal at production cutover.
3340
3344
  // - submissionMode / writeExtraProperties / syncFieldsOnPublish: see
@@ -6,8 +6,9 @@
6
6
  * conversion (with leftover CRM writes for mapped fields the HubSpot form
7
7
  * dropped), CRM upsert only, or automatic (Forms API when a GUID is linked).
8
8
  * Company find-or-create still runs after a successful submit. Timeline notes
9
- * are opt-in and only used on the CRM-upsert path. The form submission is
10
- * the lead — a CRM outage never loses it.
9
+ * (page URL, subject, answers) are optional extra context on the contact,
10
+ * alongside a native conversion. The form submission is the lead — a CRM
11
+ * outage never loses it.
11
12
  */
12
13
  import type { Core } from "@strapi/strapi";
13
14
  import { type FormDefinition, type Primitive } from "./conditions";
@@ -371,6 +371,7 @@ declare const _default: {
371
371
  submissionMode?: string;
372
372
  writeExtraProperties?: boolean;
373
373
  syncFieldsOnPublish?: boolean;
374
+ timelineNote?: boolean;
374
375
  };
375
376
  };
376
377
  body: unknown;
@@ -24,6 +24,7 @@ export interface StoredSettings {
24
24
  submissionMode?: SubmissionMode;
25
25
  writeExtraProperties?: boolean;
26
26
  syncFieldsOnPublish?: boolean;
27
+ timelineNote?: boolean;
27
28
  }
28
29
  export interface HubspotPolicy {
29
30
  /** How submissions reach HubSpot. `auto` uses Forms API when a GUID is set. */
@@ -32,6 +33,8 @@ export interface HubspotPolicy {
32
33
  writeExtraProperties: boolean;
33
34
  /** On publish, PATCH missing mapped contact fields onto the HubSpot form. */
34
35
  syncFieldsOnPublish: boolean;
36
+ /** Recap note on the contact (page URL, subject, answers) after a successful sync. */
37
+ timelineNote: boolean;
35
38
  }
36
39
  export interface PublicSettings {
37
40
  configured: boolean;
@@ -48,6 +51,7 @@ export interface PublicSettings {
48
51
  submissionMode: SubmissionMode;
49
52
  writeExtraProperties: boolean;
50
53
  syncFieldsOnPublish: boolean;
54
+ timelineNote: boolean;
51
55
  }
52
56
  export interface HubspotAccount {
53
57
  portalId: string;
@@ -62,6 +66,7 @@ interface FormsCfg {
62
66
  submissionMode?: unknown;
63
67
  writeExtraProperties?: unknown;
64
68
  syncFieldsOnPublish?: unknown;
69
+ timelineNote?: unknown;
65
70
  }
66
71
  export declare function policyFrom(stored: StoredSettings, forms: FormsCfg): HubspotPolicy;
67
72
  export declare function resolvePolicy(strapi: Core.Strapi): Promise<HubspotPolicy>;
@@ -80,6 +85,7 @@ export interface SettingsPatch {
80
85
  submissionMode?: unknown;
81
86
  writeExtraProperties?: unknown;
82
87
  syncFieldsOnPublish?: unknown;
88
+ timelineNote?: unknown;
83
89
  }
84
90
  /** Merge a PATCH-like body into the store without dropping the saved key. */
85
91
  export declare function patchStoredSettings(strapi: Core.Strapi, body: SettingsPatch): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-hubspot",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
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",