@sagepilot-ai/web-events-addon 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -91,9 +91,11 @@ Records retain event ID, occurrence time, workspace/registered installation, ori
91
91
 
92
92
  Settings → SDK publishes a text-only popup template independently from mapping versions. The installed runtime renders the published revision inside a shadow DOM, with exact page paths, delay/scroll conditions, frequency limits, required fields and keyboard dismissal/focus management. Submitting the form sets the existing contact endpoint's `marketing_consent` field to `true`. The renderer and dashboard preview have no consent checkbox or label. Drafts never render. Disabled publication removes an open popup after refresh. Native app registrations do not render website popups.
93
93
 
94
- A contact-only form saves self-reported details on a new lead and adopts its signed session. Earlier events retain their original credentials and resolve to the lead through the browser link. When email verification is enabled, the SDK adopts a customer session after a successful challenge. Phone numbers remain unverified. Form values and verification codes stay on the identity endpoints. Popup lifecycle observations obey collection permission.
94
+ A contact-only form requires a phone number and can collect an optional email. Platform API resolves a compatible phone match first, then tries a unique email match. It creates a customer when neither matches and saves the form contact as unverified. Earlier events retain their original capture owner and resolve through the browser link. When email verification is enabled, the email field is required and the link is made after the code succeeds.
95
95
 
96
- The popup handles submission/verification itself. Host-owned forms can use `submitContact({submission_id,popup_revision,name?,email?,phone?,marketing_consent})` and `verifyContact(challengeId,code)`. `logout()` immediately pauses capture and cancels pending uploads before revoking the API grant and establishing a fresh anonymous owner. Queued events retain their original ownership. The collector discards any records whose credentials the logout revoked. Existing signed ingress credentials expire within 15 minutes.
96
+ With a compatible Platform API, a successful form submission sends one `popup_submitted` event through Event Handler even when storefront analytics is off. Popup impressions, dismissals and automatic events still follow collection permission. Form values and codes stay off browser observations. FJE adds the selected customer's contact details and verification flags to attributed event history.
97
+
98
+ The popup handles submission/verification itself. Host-owned forms can use `submitContact({submission_id,popup_revision,phone,name?,email?,marketing_consent})` and `verifyContact(challengeId,code)`. `logout()` immediately pauses capture and cancels pending uploads before revoking the API grant and establishing a fresh anonymous owner. Queued events retain their original ownership. The collector discards any records whose credentials the logout revoked. Existing signed ingress credentials expire within 15 minutes.
97
99
 
98
100
  - At most 128 pending route/click/network emissions per collector, and 128 capture writes / 512 KiB of serialized handoff evidence.
99
101
  - The journal holds up to 8,192 records or 8 MiB, whichever comes first. It evicts oldest records at capacity. The 24-hour local expiry fits the server's existing offline renewal window.
package/dist/index.cjs CHANGED
@@ -237,18 +237,19 @@ var SagepilotInstallationClient = class {
237
237
  if (new TextEncoder().encode(body).byteLength > 128 * 1024) throw new Error("SDK batch exceeds the upload limit.");
238
238
  return validateSagepilotInstallationReceipt(await this.request(auth.url, { method: "POST", headers: auth.headers, body }), observations.map((item) => item.event_id));
239
239
  }
240
- /** Submits contact and adopts only a scoped lead session returned by the server. */
240
+ /** Submits contact and adopts only a scoped customer session returned by the server. */
241
241
  async submitContact(input) {
242
242
  if (!UUID.test(input.submission_id) || !Number.isSafeInteger(input.popup_revision) || input.popup_revision < 1 || typeof input.marketing_consent !== "boolean") throw new Error("Invalid popup submission.");
243
243
  if (this.transitioning) throw new Error("An SDK identity operation is already running.");
244
244
  this.transitioning = true;
245
245
  const generation = this.generation, prior = this.current;
246
246
  try {
247
- const result = await this.authenticated("/contact", input);
247
+ const body = prior?.popup_submission_events === true ? { ...input, server_submission_event: true } : input;
248
+ const result = await this.authenticated("/contact", body);
248
249
  if (!result || !["recorded", "verification_required"].includes(result.status) || result.status === "verification_required" && (!result.challenge_id || !UUID.test(result.challenge_id) || !Number.isFinite(Date.parse(result.expires_at ?? "")))) throw new Error("Invalid popup submission response.");
249
250
  const { session, ...acknowledgement } = result;
250
251
  if (session != null) {
251
- if (result.status !== "recorded" || prior?.customer_id !== null) throw new Error("Invalid popup lead session.");
252
+ if (result.status !== "recorded" || prior?.customer_id !== null) throw new Error("Invalid popup customer session.");
252
253
  await this.adoptTransition(session, prior, generation, true);
253
254
  }
254
255
  return acknowledgement;
@@ -394,7 +395,7 @@ function createSagepilotInstallationClient(options) {
394
395
 
395
396
  // package.json
396
397
  var name = "@sagepilot-ai/web-events-addon";
397
- var version = "0.2.5";
398
+ var version = "0.2.6";
398
399
 
399
400
  // src/projection.ts
400
401
  var sensitive = /password|passwd|secret|token|authorization|cookie|session|email|phone|contact|address|card|payment|cvv|ssn|dob|birth|customer|user|account|person|profile|name|description|message|content|text|search|query/i;
@@ -2946,12 +2947,12 @@ function createSagepilotWebEvents(options) {
2946
2947
  }
2947
2948
  },
2948
2949
  flush,
2949
- /** Keeps contact data on the identity endpoint and fences capture while a new lead session is adopted. */
2950
+ /** Keeps contact on the identity endpoint and fences capture while adopting the customer. */
2950
2951
  async submitContact(input) {
2951
2952
  const session = client.session();
2952
2953
  const result = session?.popup?.verification === "none" && session.customer_id === null ? await changeIdentity(() => client.submitContact(input)) : await client.submitContact(input);
2953
2954
  if (result.status === "recorded") {
2954
- emitPopup("popup_submitted");
2955
+ if (result.popup_submission_recorded !== true) emitPopup("popup_submitted");
2955
2956
  await completeVisitor(session?.anonymous_id);
2956
2957
  }
2957
2958
  return result;
@@ -2959,8 +2960,8 @@ function createSagepilotWebEvents(options) {
2959
2960
  /** Verifies proof behind a capture fence; buffered anonymous observations remain anonymous. */
2960
2961
  async verifyContact(challengeId, code) {
2961
2962
  const anonymousId = client.session()?.anonymous_id;
2962
- await changeIdentity(() => client.verifyContact(challengeId, code));
2963
- emitPopup("popup_submitted");
2963
+ const session = await changeIdentity(() => client.verifyContact(challengeId, code));
2964
+ if (session.popup_submission_recorded !== true) emitPopup("popup_submitted");
2964
2965
  await completeVisitor(anonymousId);
2965
2966
  },
2966
2967
  /** Applies an explicit logout boundary without relabeling earlier observations. */