strapi-plugin-hubspot 0.13.0 → 0.14.0

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 (34) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +59 -15
  3. package/dist/_chunks/{Forms-lrzuWzoB.js → Forms-Cch-7zei.js} +38 -3
  4. package/dist/_chunks/{Forms-CHB-sKem.mjs → Forms-ws6d8rdC.mjs} +38 -3
  5. package/dist/_chunks/{HubspotFormInput-YI09keTC.mjs → HubspotFormInput-18pWTITT.mjs} +1 -1
  6. package/dist/_chunks/{HubspotFormInput-Bb6it0nP.js → HubspotFormInput-M2l_8w_e.js} +1 -1
  7. package/dist/_chunks/{HubspotObjectInput-D3A6xzb3.js → HubspotObjectInput-BDO99qXs.js} +3 -3
  8. package/dist/_chunks/{HubspotObjectInput-CzLKT9oj.mjs → HubspotObjectInput-DshusXZP.mjs} +3 -3
  9. package/dist/_chunks/{HubspotPropertyInput-DicskLcN.mjs → HubspotPropertyInput-C-kHDgwx.mjs} +3 -3
  10. package/dist/_chunks/{HubspotPropertyInput-Dss3eUlL.js → HubspotPropertyInput-XGnH2tHn.js} +3 -3
  11. package/dist/_chunks/{Settings-4CbX3SPK.mjs → Settings-Bm7WkzK1.mjs} +2 -2
  12. package/dist/_chunks/{Settings-Ch8tPZAV.js → Settings-CRnsu6ob.js} +2 -2
  13. package/dist/_chunks/{en-PYFibnDc.js → en-BXMU5CjT.js} +4 -0
  14. package/dist/_chunks/{en-D8DJiSxd.mjs → en-DKV-8FWP.mjs} +4 -0
  15. package/dist/_chunks/{fr-yHk4sSEl.js → fr-Dx4XmZ4X.js} +4 -0
  16. package/dist/_chunks/{fr-BMjixfXn.mjs → fr-GB6T3ZyU.mjs} +4 -0
  17. package/dist/_chunks/{index-BAvedd2m.js → index-BlaG8oIq.js} +6 -6
  18. package/dist/_chunks/{index-BE2ribUL.mjs → index-CPVfElYB.mjs} +6 -6
  19. package/dist/_chunks/{objectLabels-DGJxYjKz.mjs → objectLabels-6OUnIDB5.mjs} +1 -1
  20. package/dist/_chunks/{objectLabels-CycoU0zY.js → objectLabels-CPc21Tdd.js} +1 -1
  21. package/dist/_chunks/{useHubspotSchema-DRfaI6mF.js → useHubspotSchema-0MvCM1AC.js} +1 -1
  22. package/dist/_chunks/{useHubspotSchema-e31UsYb2.mjs → useHubspotSchema-qCUs2gIX.mjs} +1 -1
  23. package/dist/admin/index.js +1 -1
  24. package/dist/admin/index.mjs +1 -1
  25. package/dist/admin/src/builder/types.d.ts +2 -0
  26. package/dist/server/index.js +425 -189
  27. package/dist/server/index.mjs +425 -189
  28. package/dist/server/src/__tests__/hsforms.test.d.ts +1 -0
  29. package/dist/server/src/content-types.d.ts +8 -0
  30. package/dist/server/src/forms.d.ts +10 -6
  31. package/dist/server/src/hsforms.d.ts +75 -0
  32. package/dist/server/src/importHubspot.d.ts +1 -0
  33. package/dist/server/src/index.d.ts +12 -1
  34. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.14.0 — 2026-09-21
6
+
7
+ ### Changed — native HubSpot form conversions
8
+ - Submissions of a built form now post to HubSpot's **Forms API**
9
+ (`/submissions/v3/integration/secure/submit/{portalId}/{formGuid}`) when a
10
+ marketing form GUID is set. That is what HubSpot counts as a conversion:
11
+ Original Source, workflows, lead-center notifications, reporting.
12
+ - The GUID is configuration, not code: pick it in the builder (or set
13
+ `forms.defaultFormId`), and swap `portalId` / `region` when moving from a
14
+ test portal to production.
15
+ - The visitor's `hubspotutk` (`meta.hutk`) is forwarded as `context.hutk` so
16
+ attribution sticks to the session.
17
+ - Extra fields not declared on the HubSpot form are dropped (they 400 the
18
+ whole submit). GDPR `legalConsentOptions` is sent when the HubSpot form
19
+ has a consent block.
20
+ - **CRM contact upsert is the fallback** when no GUID is configured. Timeline
21
+ notes remain available (`forms.timelineNote`, default `true`) on that
22
+ fallback only — they are not form conversions.
23
+ - Company find-or-create (SIRET / domain) still runs after a successful
24
+ submit, once the contact is looked up by email.
25
+
26
+ ### Added
27
+ - Form attribute `hubspotFormId` and a picker in the builder.
28
+ - Plugin config `portalId`, `region` (`eu1` by default), `forms.defaultFormId`.
29
+
30
+ ## 0.13.1 — 2026-09-21
31
+
32
+ ### Added
33
+ - **GDPR proof on submissions.** `meta.consent` / `meta.consentedAt` sent by
34
+ the frontend are stored on the submission row and written on the HubSpot
35
+ timeline note. They are not CRM properties — an unknown HubSpot key would
36
+ fail the whole upsert. Rebuild HubSpot's native legal-consent block as a
37
+ required checkbox named `consent` (see README).
38
+
3
39
  ## 0.13.0 — 2026-08-31
4
40
 
5
41
  ### Added
package/README.md CHANGED
@@ -5,9 +5,10 @@
5
5
  Build multi-step lead forms in a dedicated admin page: fields mapped to your
6
6
  portal's *real* CRM properties through a searchable picker, conditional fields
7
7
  and steps (AND/OR rules re-evaluated server-side), a public API your frontend
8
- renders and posts to, and a submission pipeline that upserts the Contact,
9
- finds-or-creates the Company by corporate domain, drops a recap note on the
10
- timeline, and stores every submission in Strapi whatever the CRM's mood.
8
+ renders and posts to, and a submission pipeline that posts a **native HubSpot
9
+ form conversion** (Forms API + visitor `hutk`), finds-or-creates the Company
10
+ by corporate domain, and stores every submission in Strapi whatever the CRM's
11
+ mood.
11
12
 
12
13
  Under it, the safety net this plugin has always been: property pickers as
13
14
  custom fields for your own content types, save-time mapping validation, a
@@ -43,20 +44,28 @@ Permissions**):
43
44
  | `GET` | `/api/hubspot/forms/:slug?locale=` | The published form — meta, steps, fields, conditions. The CRM mapping is stripped: the browser never learns your property names |
44
45
  | `POST` | `/api/hubspot/forms/:slug/submit` | Validates (bounds, conditions, required), maps server-side, syncs HubSpot, stores the submission |
45
46
 
46
- The submit pipeline, in order: contact upsert (`email` is the find-or-create
47
- key) through the plugin's sending service — pre-validation against the portal
48
- schema (a stale mapping costs one answer, never the lead), retries, replay
49
- queue; then, when the email is on a corporate domain, company found-or-created
50
- by `domain` and associated to the contact; then a timeline note recapping the
51
- answers and the lead's origin. Company and note are best-effort and can be
52
- turned off:
47
+ The submit pipeline, in order: HubSpot **Forms API** (native conversion —
48
+ Original Source, workflows, lead-center notifications) when a marketing form
49
+ GUID is set on the builder form or via `forms.defaultFormId`; the visitor's
50
+ `hutk` is forwarded so attribution sticks. Then the contact is looked up by
51
+ email and, when the address is on a corporate domain, the company is
52
+ found-or-created and associated. A CRM contact upsert is the **fallback**
53
+ when no GUID is configured — it does not count as a form conversion.
54
+ Timeline notes are opt-in and only used on that fallback.
55
+
56
+ Portal id, region and form GUIDs are configuration. A test portal today,
57
+ production tomorrow: swap `portalId` / `region` / the GUID, no code change.
53
58
 
54
59
  ```ts
55
60
  hubspot: {
56
61
  config: {
62
+ apiKey: env("HUBSPOT_API_KEY"),
63
+ portalId: env("HUBSPOT_PORTAL_ID"), // test now, production later
64
+ region: env("HUBSPOT_REGION", "eu1"), // eu1 → api-eu1.hsforms.com
57
65
  forms: {
58
66
  companyFromDomain: true, // Company by corporate domain + association
59
- timelineNote: true, // recap note on the contact (and company)
67
+ timelineNote: false, // recap note on the CRM-upsert fallback only
68
+ defaultFormId: env("HUBSPOT_DEFAULT_FORM_ID", ""),
60
69
  },
61
70
  },
62
71
  }
@@ -66,6 +75,35 @@ Every submission is stored in **HubSpot form submissions** (Content Manager),
66
75
  synced or not, with the CRM ids when the sync succeeded — the source of truth
67
76
  lives in your database, not in HubSpot's availability.
68
77
 
78
+ ### GDPR consent
79
+
80
+ HubSpot's native *legal consent* block is **not** a CRM field. Importing a
81
+ HubSpot form skips it (you'll see "rebuild it as a field"). The Forms API
82
+ submit sends `legalConsentOptions` when the HubSpot marketing form has a
83
+ GDPR block and the visitor ticked consent.
84
+
85
+ To connect consent so the CRM and Strapi both keep a proof:
86
+
87
+ 1. **In HubSpot** (Settings → Properties → Contact), create a checkbox
88
+ property, e.g. `rgpd_consent`. Optionally a datetime `rgpd_consented_at`.
89
+ 2. **In the form builder** (Admin → HubSpot Forms), last step: add a
90
+ **Checkbox**, name it `consent` (that name is what the site recognizes —
91
+ it will not inject a second box), mark it **required**.
92
+ 3. **Map it**: Object = Contact, property = `rgpd_consent`. The visitor's tick
93
+ then lands on the contact (if that property is on the HubSpot form) and in
94
+ `legalConsentOptions`. Leave `consentedAt` unmapped; the frontend sends it
95
+ in `meta.consentedAt`, stored on the submission.
96
+ 4. **Point the builder form at a HubSpot marketing form** (right-hand panel)
97
+ so the tick is a native conversion, not a CRM note.
98
+ 5. **Publish** the form. The public submit pipeline already refuses a payload
99
+ without consent when the site is in front (Nuxt BFF). Direct calls to
100
+ `/api/hubspot/forms/:slug/submit` still accept a form that has no consent
101
+ field — add the checkbox so required-field validation covers them too.
102
+
103
+ The frontend should also send `meta.hutk` (the `hubspotutk` cookie set by
104
+ HubSpot's tracking script) and `meta.pageUrl` so Original Source is Organic
105
+ Search / Direct / etc. rather than *Offline sources*.
106
+
69
107
  ### Browsing submissions
70
108
 
71
109
  The **Submissions** button on the forms list (also reachable from a form's
@@ -375,6 +413,8 @@ export default ({ env }) => ({
375
413
  config: {
376
414
  // Optional — the key can also be set from Settings → HubSpot.
377
415
  apiKey: env("HUBSPOT_API_KEY", ""),
416
+ portalId: env("HUBSPOT_PORTAL_ID", ""),
417
+ region: env("HUBSPOT_REGION", "eu1"),
378
418
 
379
419
  // Optional — objects whose properties are offered.
380
420
  // Defaults to ["contact", "company"]. Standard names: contact, company,
@@ -421,6 +461,10 @@ Create a **private app** in HubSpot with a read scope per object you list:
421
461
  - `crm.schemas.contacts.read`
422
462
  - `crm.schemas.companies.read`
423
463
  - `crm.schemas.deals.read`, `crm.schemas.custom.read`… as needed
464
+ - `crm.objects.contacts.read` / `write`, `crm.objects.companies.read` / `write`
465
+ - `forms` — list portal forms (import + builder picker) and **submit** them
466
+ via the Forms API (native conversions). Without this scope the pipeline
467
+ falls back to a CRM upsert, which HubSpot treats as an offline source.
424
468
 
425
469
  An object the token can't read is **skipped, not fatal**: the picker keeps
426
470
  working for the others and explains which one is missing a scope. `oauth` is
@@ -430,10 +474,10 @@ turn on the *view in HubSpot* links.
430
474
  ### Regions
431
475
 
432
476
  The REST API is global: `api.hubapi.com` routes by token, whatever the portal's
433
- hosting region. The **web app is not** — an EU-hosted portal lives on
434
- `app-eu1.hubspot.com`. Deep links are built from the `uiDomain` HubSpot reports
435
- for your portal rather than a hardcoded host, so they point at the right region
436
- without any configuration.
477
+ hosting region. The **web app and the Forms API are not** — an EU-hosted portal
478
+ lives on `app-eu1.hubspot.com` and submits to `api-eu1.hsforms.com`. Set
479
+ `config.region` (`eu1`, `na1`, …) to match. Deep links are built from the
480
+ `uiDomain` HubSpot reports for your portal rather than a hardcoded host.
437
481
 
438
482
  The key is resolved in this order, first match wins:
439
483
 
@@ -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-BAvedd2m.js");
10
+ const index$1 = require("./index-BlaG8oIq.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-CycoU0zY.js");
15
- const useHubspotSchema = require("./useHubspotSchema-DRfaI6mF.js");
14
+ const objectLabels = require("./objectLabels-CPc21Tdd.js");
15
+ const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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" } });
@@ -657,6 +657,7 @@ const FormEditor = () => {
657
657
  const [errors, setErrors] = React__namespace.useState([]);
658
658
  const [problems, setProblems] = React__namespace.useState([]);
659
659
  const [feedback, setFeedback] = React__namespace.useState(null);
660
+ const [hsForms, setHsForms] = React__namespace.useState([]);
660
661
  const t = (id, defaultMessage, values) => formatMessage({ id: index$1.getTranslation(id), defaultMessage }, values);
661
662
  const query = locale ? `?locale=${locale}` : "";
662
663
  React__namespace.useEffect(() => {
@@ -670,6 +671,9 @@ const FormEditor = () => {
670
671
  React__namespace.useEffect(() => {
671
672
  get("/i18n/locales").then(({ data }) => Array.isArray(data) && setLocales(data)).catch(() => setLocales([]));
672
673
  }, [get]);
674
+ React__namespace.useEffect(() => {
675
+ get(`/${index$1.PLUGIN_ID}/builder/import/hubspot`).then(({ data }) => setHsForms(Array.isArray(data.forms) ? data.forms : [])).catch(() => setHsForms([]));
676
+ }, [get]);
673
677
  React__namespace.useEffect(() => {
674
678
  let cancelled = false;
675
679
  setEntry(null);
@@ -764,6 +768,7 @@ const FormEditor = () => {
764
768
  submitLabel: entry.submitLabel,
765
769
  successMessage: entry.successMessage,
766
770
  class: entry.class,
771
+ hubspotFormId: entry.hubspotFormId ?? "",
767
772
  definition
768
773
  }
769
774
  );
@@ -1195,6 +1200,36 @@ const FormEditor = () => {
1195
1200
  }
1196
1201
  )
1197
1202
  ] }),
1203
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
1204
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: t("editor.hubspot-form", "HubSpot marketing form") }),
1205
+ hsForms.length ? /* @__PURE__ */ jsxRuntime.jsxs(
1206
+ designSystem.SingleSelect,
1207
+ {
1208
+ value: entry.hubspotFormId ?? "",
1209
+ placeholder: t(
1210
+ "editor.hubspot-form-placeholder",
1211
+ "Pick a form of the connected portal"
1212
+ ),
1213
+ onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
1214
+ children: [
1215
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
1216
+ entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
1217
+ hsForms.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: f.id, children: f.name }, f.id))
1218
+ ]
1219
+ }
1220
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1221
+ designSystem.TextInput,
1222
+ {
1223
+ value: entry.hubspotFormId ?? "",
1224
+ placeholder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
1225
+ onChange: (e) => patchEntry({ hubspotFormId: e.target.value.trim() || null })
1226
+ }
1227
+ ),
1228
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
1229
+ "editor.hubspot-form-hint",
1230
+ "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded."
1231
+ ) })
1232
+ ] }),
1198
1233
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t(
1199
1234
  "editor.form-hint",
1200
1235
  "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
@@ -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-BE2ribUL.mjs";
8
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
9
9
  import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from "@dnd-kit/core";
10
10
  import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from "@dnd-kit/sortable";
11
11
  import { CSS } from "@dnd-kit/utilities";
12
- import { o as objectLabel } from "./objectLabels-DGJxYjKz.mjs";
13
- import { u as useHubspotSchema } from "./useHubspotSchema-e31UsYb2.mjs";
12
+ import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
13
+ import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.mjs";
14
14
  const OPERATORS = [
15
15
  "eq",
16
16
  "neq",
@@ -637,6 +637,7 @@ const FormEditor = () => {
637
637
  const [errors, setErrors] = React.useState([]);
638
638
  const [problems, setProblems] = React.useState([]);
639
639
  const [feedback, setFeedback] = React.useState(null);
640
+ const [hsForms, setHsForms] = React.useState([]);
640
641
  const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
641
642
  const query = locale ? `?locale=${locale}` : "";
642
643
  React.useEffect(() => {
@@ -650,6 +651,9 @@ const FormEditor = () => {
650
651
  React.useEffect(() => {
651
652
  get("/i18n/locales").then(({ data }) => Array.isArray(data) && setLocales(data)).catch(() => setLocales([]));
652
653
  }, [get]);
654
+ React.useEffect(() => {
655
+ get(`/${PLUGIN_ID}/builder/import/hubspot`).then(({ data }) => setHsForms(Array.isArray(data.forms) ? data.forms : [])).catch(() => setHsForms([]));
656
+ }, [get]);
653
657
  React.useEffect(() => {
654
658
  let cancelled = false;
655
659
  setEntry(null);
@@ -744,6 +748,7 @@ const FormEditor = () => {
744
748
  submitLabel: entry.submitLabel,
745
749
  successMessage: entry.successMessage,
746
750
  class: entry.class,
751
+ hubspotFormId: entry.hubspotFormId ?? "",
747
752
  definition
748
753
  }
749
754
  );
@@ -1175,6 +1180,36 @@ const FormEditor = () => {
1175
1180
  }
1176
1181
  )
1177
1182
  ] }),
1183
+ /* @__PURE__ */ jsxs(Field.Root, { children: [
1184
+ /* @__PURE__ */ jsx(Field.Label, { children: t("editor.hubspot-form", "HubSpot marketing form") }),
1185
+ hsForms.length ? /* @__PURE__ */ jsxs(
1186
+ SingleSelect,
1187
+ {
1188
+ value: entry.hubspotFormId ?? "",
1189
+ placeholder: t(
1190
+ "editor.hubspot-form-placeholder",
1191
+ "Pick a form of the connected portal"
1192
+ ),
1193
+ onChange: (id) => patchEntry({ hubspotFormId: String(id) || null }),
1194
+ children: [
1195
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: t("editor.hubspot-form-none", "None — CRM upsert only") }),
1196
+ entry.hubspotFormId && !hsForms.some((f) => f.id === entry.hubspotFormId) && /* @__PURE__ */ jsx(SingleSelectOption, { value: entry.hubspotFormId, children: entry.hubspotFormId }),
1197
+ hsForms.map((f) => /* @__PURE__ */ jsx(SingleSelectOption, { value: f.id, children: f.name }, f.id))
1198
+ ]
1199
+ }
1200
+ ) : /* @__PURE__ */ jsx(
1201
+ TextInput,
1202
+ {
1203
+ value: entry.hubspotFormId ?? "",
1204
+ placeholder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
1205
+ onChange: (e) => patchEntry({ hubspotFormId: e.target.value.trim() || null })
1206
+ }
1207
+ ),
1208
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
1209
+ "editor.hubspot-form-hint",
1210
+ "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded."
1211
+ ) })
1212
+ ] }),
1178
1213
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t(
1179
1214
  "editor.form-hint",
1180
1215
  "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
@@ -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-BE2ribUL.mjs";
6
+ import { P as PLUGIN_ID, g as getTranslation } from "./index-CPVfElYB.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-BAvedd2m.js");
8
+ const index$1 = require("./index-BlaG8oIq.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" } });
@@ -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-BAvedd2m.js");
8
- const objectLabels = require("./objectLabels-CycoU0zY.js");
9
- const useHubspotSchema = require("./useHubspotSchema-DRfaI6mF.js");
7
+ const index$1 = require("./index-BlaG8oIq.js");
8
+ const objectLabels = require("./objectLabels-CPc21Tdd.js");
9
+ const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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-BE2ribUL.mjs";
6
- import { o as objectLabel } from "./objectLabels-DGJxYjKz.mjs";
7
- import { u as useHubspotSchema } from "./useHubspotSchema-e31UsYb2.mjs";
5
+ import { g as getTranslation } from "./index-CPVfElYB.mjs";
6
+ import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
7
+ import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.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 @@ 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-BE2ribUL.mjs";
8
- import { o as objectLabel } from "./objectLabels-DGJxYjKz.mjs";
9
- import { u as useHubspotSchema } from "./useHubspotSchema-e31UsYb2.mjs";
7
+ import { g as getTranslation } from "./index-CPVfElYB.mjs";
8
+ import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
9
+ import { u as useHubspotSchema } from "./useHubspotSchema-qCUs2gIX.mjs";
10
10
  const oneLine = {
11
11
  display: "block",
12
12
  whiteSpace: "nowrap",
@@ -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-BAvedd2m.js");
10
- const objectLabels = require("./objectLabels-CycoU0zY.js");
11
- const useHubspotSchema = require("./useHubspotSchema-DRfaI6mF.js");
9
+ const index$1 = require("./index-BlaG8oIq.js");
10
+ const objectLabels = require("./objectLabels-CPc21Tdd.js");
11
+ const useHubspotSchema = require("./useHubspotSchema-0MvCM1AC.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" } });
@@ -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 } from "@strapi/design-system";
5
5
  import { useFetchClient } from "@strapi/strapi/admin";
6
- import { g as getTranslation, P as PLUGIN_ID } from "./index-BE2ribUL.mjs";
6
+ import { g as getTranslation, P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
7
7
  import { Link as Link$1 } from "react-router-dom";
8
- import { o as objectLabel } from "./objectLabels-DGJxYjKz.mjs";
8
+ import { o as objectLabel } from "./objectLabels-6OUnIDB5.mjs";
9
9
  const AuditSection = ({ configured }) => {
10
10
  const intl = useIntl();
11
11
  const { formatMessage } = intl;
@@ -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-BAvedd2m.js");
8
+ const index$1 = require("./index-BlaG8oIq.js");
9
9
  const reactRouterDom = require("react-router-dom");
10
- const objectLabels = require("./objectLabels-CycoU0zY.js");
10
+ const objectLabels = require("./objectLabels-CPc21Tdd.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" } });
@@ -141,6 +141,10 @@ const en = {
141
141
  "editor.form-next": "Next label",
142
142
  "editor.form-submit": "Submit label",
143
143
  "editor.form-success": "Success message",
144
+ "editor.hubspot-form": "HubSpot marketing form",
145
+ "editor.hubspot-form-placeholder": "Pick a form of the connected portal",
146
+ "editor.hubspot-form-none": "None — CRM upsert only",
147
+ "editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded.",
144
148
  "editor.form-hint": "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
145
149
  "panel.label": "Label",
146
150
  "panel.name": "Payload key",
@@ -139,6 +139,10 @@ const en = {
139
139
  "editor.form-next": "Next label",
140
140
  "editor.form-submit": "Submit label",
141
141
  "editor.form-success": "Success message",
142
+ "editor.hubspot-form": "HubSpot marketing form",
143
+ "editor.hubspot-form-placeholder": "Pick a form of the connected portal",
144
+ "editor.hubspot-form-none": "None — CRM upsert only",
145
+ "editor.hubspot-form-hint": "Submissions go through HubSpot’s Forms API so they count as conversions. Switch the connected portal (test → production) and pick the matching form — nothing is hardcoded.",
142
146
  "editor.form-hint": "Select a step or a field to edit it. The public endpoint serves this form at /api/hubspot/forms/{slug}.",
143
147
  "panel.label": "Label",
144
148
  "panel.name": "Payload key",
@@ -141,6 +141,10 @@ const fr = {
141
141
  "editor.form-next": "Libellé Suivant",
142
142
  "editor.form-submit": "Libellé Envoyer",
143
143
  "editor.form-success": "Message de succès",
144
+ "editor.hubspot-form": "Formulaire marketing HubSpot",
145
+ "editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
146
+ "editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
147
+ "editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Changez de portail (test → prod) et sélectionnez le formulaire correspondant — rien n’est figé dans le code.",
144
148
  "editor.form-hint": "Sélectionnez une étape ou un champ pour l'éditer. Le endpoint public sert ce formulaire sur /api/hubspot/forms/{slug}.",
145
149
  "panel.label": "Libellé",
146
150
  "panel.name": "Clé du payload",
@@ -139,6 +139,10 @@ const fr = {
139
139
  "editor.form-next": "Libellé Suivant",
140
140
  "editor.form-submit": "Libellé Envoyer",
141
141
  "editor.form-success": "Message de succès",
142
+ "editor.hubspot-form": "Formulaire marketing HubSpot",
143
+ "editor.hubspot-form-placeholder": "Choisir un formulaire du portail connecté",
144
+ "editor.hubspot-form-none": "Aucun — upsert CRM uniquement",
145
+ "editor.hubspot-form-hint": "Les envois passent par l’API Forms de HubSpot pour compter comme des conversions. Changez de portail (test → prod) et sélectionnez le formulaire correspondant — rien n’est figé dans le code.",
142
146
  "editor.form-hint": "Sélectionnez une étape ou un champ pour l'éditer. Le endpoint public sert ce formulaire sur /api/hubspot/forms/{slug}.",
143
147
  "panel.label": "Libellé",
144
148
  "panel.name": "Clé du payload",
@@ -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-lrzuWzoB.js"))).default
29
+ Component: async () => (await Promise.resolve().then(() => require("./Forms-Cch-7zei.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-Dss3eUlL.js"))
44
+ Input: async () => Promise.resolve().then(() => require("./HubspotPropertyInput-XGnH2tHn.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-D3A6xzb3.js"))
107
+ Input: async () => Promise.resolve().then(() => require("./HubspotObjectInput-BDO99qXs.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-Bb6it0nP.js"))
123
+ Input: async () => Promise.resolve().then(() => require("./HubspotFormInput-M2l_8w_e.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-Ch8tPZAV.js"))).default
139
+ Component: async () => (await Promise.resolve().then(() => require("./Settings-CRnsu6ob.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-PYFibnDc.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-yHk4sSEl.js")) }), `./translations/${locale}.json`, 3);
149
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-BXMU5CjT.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-Dx4XmZ4X.js")) }), `./translations/${locale}.json`, 3);
150
150
  return { data: prefixPluginTranslations(data), locale };
151
151
  } catch {
152
152
  return { data: {}, locale };
@@ -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-CHB-sKem.mjs")).default
28
+ Component: async () => (await import("./Forms-ws6d8rdC.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-DicskLcN.mjs")
43
+ Input: async () => import("./HubspotPropertyInput-C-kHDgwx.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-CzLKT9oj.mjs")
106
+ Input: async () => import("./HubspotObjectInput-DshusXZP.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-YI09keTC.mjs")
122
+ Input: async () => import("./HubspotFormInput-18pWTITT.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-4CbX3SPK.mjs")).default
138
+ Component: async () => (await import("./Settings-Bm7WkzK1.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-D8DJiSxd.mjs"), "./translations/fr.json": () => import("./fr-BMjixfXn.mjs") }), `./translations/${locale}.json`, 3);
148
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-DKV-8FWP.mjs"), "./translations/fr.json": () => import("./fr-GB6T3ZyU.mjs") }), `./translations/${locale}.json`, 3);
149
149
  return { data: prefixPluginTranslations(data), locale };
150
150
  } catch {
151
151
  return { data: {}, locale };
@@ -1,4 +1,4 @@
1
- import { g as getTranslation } from "./index-BE2ribUL.mjs";
1
+ import { g as getTranslation } from "./index-CPVfElYB.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-BAvedd2m.js");
2
+ const index = require("./index-BlaG8oIq.js");
3
3
  const STANDARD = /* @__PURE__ */ new Set([
4
4
  "contact",
5
5
  "company",
@@ -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-BAvedd2m.js");
4
+ const index = require("./index-BlaG8oIq.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-BE2ribUL.mjs";
3
+ import { P as PLUGIN_ID } from "./index-CPVfElYB.mjs";
4
4
  let cached = null;
5
5
  let inFlight = null;
6
6
  const listeners = /* @__PURE__ */ new Set();
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-BAvedd2m.js");
2
+ const index = require("../_chunks/index-BlaG8oIq.js");
3
3
  require("@strapi/icons");
4
4
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-BE2ribUL.mjs";
1
+ import { i } from "../_chunks/index-CPVfElYB.mjs";
2
2
  import "@strapi/icons";
3
3
  export {
4
4
  i as default