glitchgrab 1.56.0 → 1.57.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.
package/README.md CHANGED
@@ -288,6 +288,35 @@ curl "https://glitchgrab.dev/api/v1/sdk/feedback?approved=true&minRating=4&limit
288
288
 
289
289
  The repo is always derived from the token — there is no `repoId` to pass. Rate limit: 30 submissions per token per hour.
290
290
 
291
+ ## How do I save a lead without filing an issue?
292
+
293
+ A demo form or contact page asks a prospect for their details. Those are a **lead**, not a bug — `submitLead()` stores them in Glitchgrab and never creates a GitHub issue:
294
+
295
+ ```tsx
296
+ const { submitLead } = useGlitchgrab();
297
+
298
+ const result = await submitLead({
299
+ name: "Asha Mehta",
300
+ phone: "+91 98765 43210",
301
+ source: "demo", // which form — filter on it later
302
+ email: "asha@firm.in", // optional
303
+ company: "Mehta & Co", // optional
304
+ address: "Pune", // optional
305
+ metadata: { practice: "CA", language: "Hindi" }, // optional, flat values
306
+ });
307
+ // { success: true, id: "…", created: true } — or null on failure. Never throws.
308
+ ```
309
+
310
+ One lead per phone number per project: the same visitor submitting twice updates their lead (`created: false`) instead of adding a second row. Leads show under **Calls → Leads** in Glitchgrab, next to any demo the same phone or email went on to book. The owner can switch on a WhatsApp alert for each new lead there.
311
+
312
+ Read them in your own admin with the project's `ggc_` server key — the same key as `listBookings()`:
313
+
314
+ ```ts
315
+ import { listLeads } from "glitchgrab/server";
316
+
317
+ const leads = await listLeads({ source: "demo", since: "2026-09-01" }); // GLITCHGRAB_CALLS_KEY=ggc_…
318
+ ```
319
+
291
320
  ## What keyboard shortcuts are available?
292
321
 
293
322
  Once `GlitchgrabProvider` is mounted, these shortcuts work globally:
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { f as GlitchgrabProviderProps, U as UseGlitchgrabReturn, R as ReportButtonProps, F as FeedbackButtonProps, g as GlitchgrabSession, C as CaptureErrorOptions, e as GlitchgrabFeedback, a as BreadcrumbType, B as Breadcrumb, b as CapturedContext, D as DeviceInfo, c as FeedbackPayload, d as FeedbackResult, h as ReportPayload, i as ReportResult } from './types-DcDF1mXc.mjs';
3
- export { G as GlitchgrabConfig, j as ReportSeverity, k as ReportType, l as RuntimeInfo } from './types-DcDF1mXc.mjs';
2
+ import { f as GlitchgrabProviderProps, U as UseGlitchgrabReturn, R as ReportButtonProps, F as FeedbackButtonProps, g as GlitchgrabSession, C as CaptureErrorOptions, e as GlitchgrabFeedback, a as BreadcrumbType, B as Breadcrumb, b as CapturedContext, D as DeviceInfo, c as FeedbackPayload, d as FeedbackResult, L as LeadInput, h as LeadResult, i as ReportPayload, j as ReportResult } from './types-DfVtKZcp.mjs';
3
+ export { G as GlitchgrabConfig, k as ReportSeverity, l as ReportType, m as RuntimeInfo } from './types-DfVtKZcp.mjs';
4
4
  import * as React from 'react';
5
5
  import { ReactNode } from 'react';
6
6
 
@@ -356,6 +356,13 @@ declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<R
356
356
  * sendBeacon fallback: the caller needs a real result to show a thank-you.
357
357
  */
358
358
  declare function sendFeedback(payload: FeedbackPayload, baseUrl?: string): Promise<FeedbackResult | null>;
359
+ /**
360
+ * POST a lead (#534). Retries transient failures like {@link sendFeedback}; a
361
+ * 4xx other than 429 is a caller mistake and returns null at once.
362
+ */
363
+ declare function sendLead(token: string, lead: LeadInput & {
364
+ pageUrl?: string;
365
+ }, baseUrl?: string): Promise<LeadResult | null>;
359
366
  interface EnhanceContext {
360
367
  url?: string;
361
368
  visitedPages?: string[];
@@ -397,4 +404,4 @@ declare function computeSignature(params: {
397
404
  declare function shouldSkipDuplicate(signature: string, windowMs?: number, now?: number): boolean;
398
405
  declare function clearDedupCache(): void;
399
406
 
400
- export { BookDemoButton, Breadcrumb, BreadcrumbType, CaptureErrorOptions, CapturedContext, DeviceInfo, FeedbackButton, FeedbackButtonProps, FeedbackPayload, type FeedbackQuery, FeedbackResult, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, GlitchgrabErrorBoundary, GlitchgrabFeedback, GlitchgrabProvider, GlitchgrabProviderProps, type GlitchgrabReport, GlitchgrabSession, ReportButton, ReportButtonProps, ReportPayload, ReportResult, UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, captureError, clearAppContext, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabFeedback, fetchGlitchgrabReports, getAppContext, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendFeedback, sendReport, setContext, setContexts, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabFeedback, useGlitchgrabReports };
407
+ export { BookDemoButton, Breadcrumb, BreadcrumbType, CaptureErrorOptions, CapturedContext, DeviceInfo, FeedbackButton, FeedbackButtonProps, FeedbackPayload, type FeedbackQuery, FeedbackResult, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, GlitchgrabErrorBoundary, GlitchgrabFeedback, GlitchgrabProvider, GlitchgrabProviderProps, type GlitchgrabReport, GlitchgrabSession, LeadInput, LeadResult, ReportButton, ReportButtonProps, ReportPayload, ReportResult, UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, captureError, clearAppContext, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabFeedback, fetchGlitchgrabReports, getAppContext, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendFeedback, sendLead, sendReport, setContext, setContexts, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabFeedback, useGlitchgrabReports };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { f as GlitchgrabProviderProps, U as UseGlitchgrabReturn, R as ReportButtonProps, F as FeedbackButtonProps, g as GlitchgrabSession, C as CaptureErrorOptions, e as GlitchgrabFeedback, a as BreadcrumbType, B as Breadcrumb, b as CapturedContext, D as DeviceInfo, c as FeedbackPayload, d as FeedbackResult, h as ReportPayload, i as ReportResult } from './types-DcDF1mXc.js';
3
- export { G as GlitchgrabConfig, j as ReportSeverity, k as ReportType, l as RuntimeInfo } from './types-DcDF1mXc.js';
2
+ import { f as GlitchgrabProviderProps, U as UseGlitchgrabReturn, R as ReportButtonProps, F as FeedbackButtonProps, g as GlitchgrabSession, C as CaptureErrorOptions, e as GlitchgrabFeedback, a as BreadcrumbType, B as Breadcrumb, b as CapturedContext, D as DeviceInfo, c as FeedbackPayload, d as FeedbackResult, L as LeadInput, h as LeadResult, i as ReportPayload, j as ReportResult } from './types-DfVtKZcp.js';
3
+ export { G as GlitchgrabConfig, k as ReportSeverity, l as ReportType, m as RuntimeInfo } from './types-DfVtKZcp.js';
4
4
  import * as React from 'react';
5
5
  import { ReactNode } from 'react';
6
6
 
@@ -356,6 +356,13 @@ declare function sendReport(payload: ReportPayload, baseUrl?: string): Promise<R
356
356
  * sendBeacon fallback: the caller needs a real result to show a thank-you.
357
357
  */
358
358
  declare function sendFeedback(payload: FeedbackPayload, baseUrl?: string): Promise<FeedbackResult | null>;
359
+ /**
360
+ * POST a lead (#534). Retries transient failures like {@link sendFeedback}; a
361
+ * 4xx other than 429 is a caller mistake and returns null at once.
362
+ */
363
+ declare function sendLead(token: string, lead: LeadInput & {
364
+ pageUrl?: string;
365
+ }, baseUrl?: string): Promise<LeadResult | null>;
359
366
  interface EnhanceContext {
360
367
  url?: string;
361
368
  visitedPages?: string[];
@@ -397,4 +404,4 @@ declare function computeSignature(params: {
397
404
  declare function shouldSkipDuplicate(signature: string, windowMs?: number, now?: number): boolean;
398
405
  declare function clearDedupCache(): void;
399
406
 
400
- export { BookDemoButton, Breadcrumb, BreadcrumbType, CaptureErrorOptions, CapturedContext, DeviceInfo, FeedbackButton, FeedbackButtonProps, FeedbackPayload, type FeedbackQuery, FeedbackResult, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, GlitchgrabErrorBoundary, GlitchgrabFeedback, GlitchgrabProvider, GlitchgrabProviderProps, type GlitchgrabReport, GlitchgrabSession, ReportButton, ReportButtonProps, ReportPayload, ReportResult, UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, captureError, clearAppContext, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabFeedback, fetchGlitchgrabReports, getAppContext, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendFeedback, sendReport, setContext, setContexts, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabFeedback, useGlitchgrabReports };
407
+ export { BookDemoButton, Breadcrumb, BreadcrumbType, CaptureErrorOptions, CapturedContext, DeviceInfo, FeedbackButton, FeedbackButtonProps, FeedbackPayload, type FeedbackQuery, FeedbackResult, GLITCHGRAB_SHORTCUT, GLITCHGRAB_SHORTCUT_MAC, GlitchgrabErrorBoundary, GlitchgrabFeedback, GlitchgrabProvider, GlitchgrabProviderProps, type GlitchgrabReport, GlitchgrabSession, LeadInput, LeadResult, ReportButton, ReportButtonProps, ReportPayload, ReportResult, UseGlitchgrabReturn, addBreadcrumb, captureContext, captureDeviceInfo, captureError, clearAppContext, clearBreadcrumbs, clearDedupCache, computeSignature, enhanceText, fetchGlitchgrabFeedback, fetchGlitchgrabReports, getAppContext, getBreadcrumbs, getShortcutLabel, initBreadcrumbs, matchesShortcut, sanitizeUrl, sendFeedback, sendLead, sendReport, setContext, setContexts, shouldSkipDuplicate, useGlitchgrab, useGlitchgrabActions, useGlitchgrabFeedback, useGlitchgrabReports };
package/dist/index.js CHANGED
@@ -56,6 +56,7 @@ __export(index_exports, {
56
56
  matchesShortcut: () => matchesShortcut,
57
57
  sanitizeUrl: () => sanitizeUrl,
58
58
  sendFeedback: () => sendFeedback,
59
+ sendLead: () => sendLead,
59
60
  sendReport: () => sendReport,
60
61
  setContext: () => setContext,
61
62
  setContexts: () => setContexts,
@@ -724,6 +725,36 @@ async function sendFeedback(payload, baseUrl) {
724
725
  return null;
725
726
  }
726
727
  }
728
+ async function sendLead(token, lead, baseUrl) {
729
+ var _a, _b;
730
+ try {
731
+ const url = `${baseUrl != null ? baseUrl : DEFAULT_BASE_URL}/api/v1/sdk/leads`;
732
+ const body = JSON.stringify(lead);
733
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
734
+ try {
735
+ const response = await fetch(url, {
736
+ method: "POST",
737
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
738
+ body
739
+ });
740
+ if (response.ok) {
741
+ const envelope = await response.json();
742
+ return { success: envelope.success, id: (_a = envelope.data) == null ? void 0 : _a.leadId, created: (_b = envelope.data) == null ? void 0 : _b.created };
743
+ }
744
+ if (response.status >= 400 && response.status < 500 && response.status !== 429) {
745
+ return null;
746
+ }
747
+ } catch (e) {
748
+ }
749
+ if (attempt < MAX_RETRIES - 1) {
750
+ await new Promise((resolve) => setTimeout(resolve, RETRY_BASE_MS * Math.pow(2, attempt)));
751
+ }
752
+ }
753
+ return null;
754
+ } catch (e) {
755
+ return null;
756
+ }
757
+ }
727
758
  function signedFields(identity) {
728
759
  if (!(identity == null ? void 0 : identity.signature) || !identity.userId) return {};
729
760
  return { userId: identity.userId, signature: identity.signature };
@@ -9127,6 +9158,17 @@ function GlitchgrabProviderInner({
9127
9158
  },
9128
9159
  [token, baseUrl, session]
9129
9160
  );
9161
+ const submitLead = (0, import_react6.useCallback)(
9162
+ async (lead) => {
9163
+ try {
9164
+ const context = captureContext(visitedPagesRef.current);
9165
+ return await sendLead(token, { ...lead, pageUrl: context.url }, baseUrl);
9166
+ } catch (e) {
9167
+ return null;
9168
+ }
9169
+ },
9170
+ [token, baseUrl]
9171
+ );
9130
9172
  const openFeedbackDialog = (0, import_react6.useCallback)(() => {
9131
9173
  if (typeof window !== "undefined") {
9132
9174
  window.dispatchEvent(
@@ -9304,6 +9346,7 @@ function GlitchgrabProviderInner({
9304
9346
  setContext: setContext2,
9305
9347
  setContexts: setContexts2,
9306
9348
  sendFeedback: feedback,
9349
+ submitLead,
9307
9350
  openFeedbackDialog,
9308
9351
  addBreadcrumb: addBreadcrumb2,
9309
9352
  openReportDialog,
@@ -9769,6 +9812,7 @@ function useGlitchgrabFeedback(query) {
9769
9812
  matchesShortcut,
9770
9813
  sanitizeUrl,
9771
9814
  sendFeedback,
9815
+ sendLead,
9772
9816
  sendReport,
9773
9817
  setContext,
9774
9818
  setContexts,