@asksable/site-connector 0.3.2 → 0.4.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 +46 -7
- package/dist/analytics.d.ts +18 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +94 -0
- package/dist/analytics.js.map +1 -0
- package/dist/booking-widget.d.ts.map +1 -1
- package/dist/booking-widget.js +226 -53
- package/dist/booking-widget.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +4 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +70 -2
- package/dist/provider.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Use this package in public website repos that should:
|
|
|
9
9
|
- read business/site profile data from Sable
|
|
10
10
|
- submit contact forms into Sable
|
|
11
11
|
- render the shared booking widget against Sable public booking APIs
|
|
12
|
+
- send web analytics into the separate `Sable Websites` PostHog project
|
|
12
13
|
|
|
13
14
|
## Setup
|
|
14
15
|
|
|
@@ -17,7 +18,7 @@ Wrap the site in `SableSiteProvider`:
|
|
|
17
18
|
```tsx
|
|
18
19
|
import { SableSiteProvider } from '@asksable/site-connector'
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
;<SableSiteProvider
|
|
21
22
|
config={{
|
|
22
23
|
apiUrl: import.meta.env.VITE_SABLE_PUBLIC_API_URL,
|
|
23
24
|
siteSlug: import.meta.env.VITE_SABLE_SITE_SLUG,
|
|
@@ -27,10 +28,48 @@ import { SableSiteProvider } from '@asksable/site-connector'
|
|
|
27
28
|
</SableSiteProvider>
|
|
28
29
|
```
|
|
29
30
|
|
|
31
|
+
## Website analytics
|
|
32
|
+
|
|
33
|
+
`SableSiteProvider` initializes PostHog automatically when the public
|
|
34
|
+
`/public/site-profile` response includes an enabled analytics config. This is
|
|
35
|
+
the preferred path because Sable can rotate the `Sable Websites` project token
|
|
36
|
+
centrally from Convex env vars without editing every customer website.
|
|
37
|
+
|
|
38
|
+
If a standalone host needs to override the server-provided config, pass:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
<SableSiteProvider
|
|
42
|
+
config={{
|
|
43
|
+
apiUrl,
|
|
44
|
+
siteSlug,
|
|
45
|
+
analytics: {
|
|
46
|
+
captureEnabled: true,
|
|
47
|
+
posthogToken: import.meta.env.VITE_SABLE_WEBSITES_POSTHOG_TOKEN,
|
|
48
|
+
posthogHost: 'https://us.i.posthog.com',
|
|
49
|
+
environment: import.meta.env.MODE,
|
|
50
|
+
},
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<App />
|
|
54
|
+
</SableSiteProvider>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The connector captures `$pageview` events with `sable_site_slug` and related
|
|
58
|
+
site properties, plus booking-widget conversion events:
|
|
59
|
+
|
|
60
|
+
- `sable_booking_widget_viewed`
|
|
61
|
+
- `sable_booking_service_selected`
|
|
62
|
+
- `sable_booking_created`
|
|
63
|
+
- `sable_booking_payment_started`
|
|
64
|
+
- `sable_booking_rescheduled`
|
|
65
|
+
|
|
30
66
|
Then consume the profile or render the shared booking widget:
|
|
31
67
|
|
|
32
68
|
```tsx
|
|
33
|
-
import {
|
|
69
|
+
import {
|
|
70
|
+
BookingWidgetPanel,
|
|
71
|
+
useSableSiteProfile,
|
|
72
|
+
} from '@asksable/site-connector'
|
|
34
73
|
```
|
|
35
74
|
|
|
36
75
|
## Exports
|
|
@@ -75,11 +114,11 @@ Supported locales: `'en'` (default), `'es'`. Adding a locale requires a package
|
|
|
75
114
|
|
|
76
115
|
### Three usage modes
|
|
77
116
|
|
|
78
|
-
| Site type
|
|
79
|
-
|
|
|
80
|
-
| **Single-language site (English only)** | Omit `language` entirely or pass `'en'`. Widget defaults to English.
|
|
81
|
-
| **Single-language site (Spanish only)** | Pass `language: 'es'` once at provider mount.
|
|
82
|
-
| **Multi-language site with a toggle**
|
|
117
|
+
| Site type | Pattern |
|
|
118
|
+
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| **Single-language site (English only)** | Omit `language` entirely or pass `'en'`. Widget defaults to English. |
|
|
120
|
+
| **Single-language site (Spanish only)** | Pass `language: 'es'` once at provider mount. |
|
|
121
|
+
| **Multi-language site with a toggle** | Pass a reactive value that updates when the toggle changes. The provider re-renders, the widget re-renders with the new locale. |
|
|
83
122
|
|
|
84
123
|
### Multi-language example
|
|
85
124
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Properties } from 'posthog-js';
|
|
2
|
+
import type { PublicSiteProfile, SableSiteAnalyticsConfig } from './types.js';
|
|
3
|
+
type SiteAnalyticsContext = {
|
|
4
|
+
siteSlug: string;
|
|
5
|
+
siteId?: string;
|
|
6
|
+
siteName?: string;
|
|
7
|
+
businessName?: string;
|
|
8
|
+
environment?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function initializeSableSiteAnalytics({ config, siteProfile, context, }: {
|
|
11
|
+
config: SableSiteAnalyticsConfig | undefined;
|
|
12
|
+
siteProfile: PublicSiteProfile | null;
|
|
13
|
+
context: SiteAnalyticsContext;
|
|
14
|
+
}): Promise<boolean>;
|
|
15
|
+
export declare function captureSableSitePageview(context: SiteAnalyticsContext): void;
|
|
16
|
+
export declare function captureSableSiteEvent(event: string, properties: Properties | undefined, context: SiteAnalyticsContext): void;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA0B,UAAU,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAS7E,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAwCD,wBAAsB,4BAA4B,CAAC,EACjD,MAAM,EACN,WAAW,EACX,OAAO,GACR,EAAE;IACD,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAA;IAC5C,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACrC,OAAO,EAAE,oBAAoB,CAAA;CAC9B,oBAmDA;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,oBAAoB,QAGrE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,OAAO,EAAE,oBAAoB,QAO9B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const INSTANCE_NAME = 'sableWebsites';
|
|
2
|
+
const DEFAULT_POSTHOG_HOST = 'https://us.i.posthog.com';
|
|
3
|
+
let activeClient = null;
|
|
4
|
+
let activeKey = null;
|
|
5
|
+
function getBrowserPostHogInstance() {
|
|
6
|
+
if (typeof window === 'undefined')
|
|
7
|
+
return null;
|
|
8
|
+
const globalPostHog = window.posthog;
|
|
9
|
+
return globalPostHog?.[INSTANCE_NAME] ?? activeClient;
|
|
10
|
+
}
|
|
11
|
+
function cleanHost(value) {
|
|
12
|
+
return value?.trim().replace(/\/+$/, '') || DEFAULT_POSTHOG_HOST;
|
|
13
|
+
}
|
|
14
|
+
function getContextProperties(context) {
|
|
15
|
+
return {
|
|
16
|
+
sable_site_slug: context.siteSlug,
|
|
17
|
+
sable_site_id: context.siteId,
|
|
18
|
+
sable_site_name: context.siteName,
|
|
19
|
+
sable_business_name: context.businessName,
|
|
20
|
+
sable_environment: context.environment ?? 'production',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function getPageProperties(context) {
|
|
24
|
+
if (typeof window === 'undefined')
|
|
25
|
+
return getContextProperties(context);
|
|
26
|
+
return {
|
|
27
|
+
...getContextProperties(context),
|
|
28
|
+
$current_url: window.location.href,
|
|
29
|
+
$host: window.location.host,
|
|
30
|
+
$pathname: window.location.pathname,
|
|
31
|
+
$referrer: document.referrer || undefined,
|
|
32
|
+
sable_pathname: window.location.pathname || '/',
|
|
33
|
+
sable_search: window.location.search || undefined,
|
|
34
|
+
sable_title: document.title || undefined,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export async function initializeSableSiteAnalytics({ config, siteProfile, context, }) {
|
|
38
|
+
if (typeof window === 'undefined')
|
|
39
|
+
return false;
|
|
40
|
+
const token = config?.posthogToken?.trim();
|
|
41
|
+
const captureEnabled = config?.captureEnabled === true && Boolean(token);
|
|
42
|
+
const client = getBrowserPostHogInstance();
|
|
43
|
+
if (!captureEnabled || !token) {
|
|
44
|
+
client?.opt_out_capturing();
|
|
45
|
+
activeClient = client;
|
|
46
|
+
activeKey = null;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const host = cleanHost(config.posthogHost);
|
|
50
|
+
const environment = config.environment ?? context.environment ?? 'production';
|
|
51
|
+
const key = [
|
|
52
|
+
token,
|
|
53
|
+
host,
|
|
54
|
+
environment,
|
|
55
|
+
context.siteSlug,
|
|
56
|
+
siteProfile?.site._id ?? '',
|
|
57
|
+
].join('|');
|
|
58
|
+
const posthogModule = await import('posthog-js');
|
|
59
|
+
const posthog = posthogModule.default;
|
|
60
|
+
const options = {
|
|
61
|
+
api_host: host,
|
|
62
|
+
defaults: '2026-01-30',
|
|
63
|
+
capture_pageview: false,
|
|
64
|
+
capture_pageleave: true,
|
|
65
|
+
capture_dead_clicks: true,
|
|
66
|
+
opt_out_useragent_filter: environment === 'production',
|
|
67
|
+
person_profiles: 'never',
|
|
68
|
+
request_batching: environment === 'production',
|
|
69
|
+
persistence: 'localStorage+cookie',
|
|
70
|
+
};
|
|
71
|
+
if (activeKey === key && activeClient) {
|
|
72
|
+
activeClient.register(getContextProperties({ ...context, environment }));
|
|
73
|
+
activeClient.opt_in_capturing();
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
posthog.init(token, options, INSTANCE_NAME);
|
|
77
|
+
activeClient = posthog[INSTANCE_NAME] ?? posthog;
|
|
78
|
+
activeKey = key;
|
|
79
|
+
activeClient.register(getContextProperties({ ...context, environment }));
|
|
80
|
+
activeClient.opt_in_capturing();
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
export function captureSableSitePageview(context) {
|
|
84
|
+
const client = getBrowserPostHogInstance();
|
|
85
|
+
client?.capture('$pageview', getPageProperties(context));
|
|
86
|
+
}
|
|
87
|
+
export function captureSableSiteEvent(event, properties, context) {
|
|
88
|
+
const client = getBrowserPostHogInstance();
|
|
89
|
+
client?.capture(event, {
|
|
90
|
+
...getPageProperties(context),
|
|
91
|
+
...properties,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-widget.d.ts","sourceRoot":"","sources":["../src/booking-widget.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"booking-widget.d.ts","sourceRoot":"","sources":["../src/booking-widget.tsx"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAcd,OAAO,qBAAqB,CAAA;AAmE5B;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,aAAa,EAAE,MAAM,CAAA;IACrB;;qBAEiB;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB;qCACiC;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB;;sBAEkB;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;yCACqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;oEACgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,SAAS,CAAA;IACxB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAA;IAC9B,iBAAiB,CAAC,EAAE,wBAAwB,CAAA;IAC5C;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC1B,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE,MAAM,CAAA;KACnB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,cAAc,GAAG,iBAAiB,CAAA;IAC9E,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AAKD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,WAAW,EACX,YAAY,EACZ,IAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,mBAAyB,EACzB,eAAe,EACf,iBAAiB,GAClB,EAAE,kBAAkB,2CA+tFpB"}
|