@aranova/tracking-next 0.12.0 → 0.12.2

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
@@ -14,12 +14,12 @@ Install the tracking middleware so `gclid`, `fbclid`, and UTM params are written
14
14
 
15
15
  ```ts
16
16
  // middleware.ts
17
- import { createTrackingMiddleware } from '@aranova/tracking-next/middleware';
17
+ import { createTrackingMiddleware } from "@aranova/tracking-next/middleware";
18
18
 
19
19
  export default createTrackingMiddleware();
20
20
 
21
21
  export const config = {
22
- matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
22
+ matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
23
23
  };
24
24
  ```
25
25
 
@@ -29,7 +29,7 @@ Create one shared tracking module and use its scoped exports throughout your app
29
29
 
30
30
  ```ts
31
31
  // lib/tracking.ts
32
- import { createTracking } from '@aranova/tracking-next';
32
+ import { createTracking } from "@aranova/tracking-next";
33
33
 
34
34
  export const { TrackingProvider, useTracking } = createTracking({
35
35
  apiKey: process.env.NEXT_PUBLIC_ARANOVA_TRACKING_API_KEY!,
@@ -39,7 +39,7 @@ export const { TrackingProvider, useTracking } = createTracking({
39
39
  page_view: {},
40
40
  time_on_site: { thresholdSeconds: 60 },
41
41
  specific_page_visit: {
42
- pages: [{ name: 'contact_page', pathPattern: /^\/(contact|book|get-started)/ }],
42
+ pages: [{ name: "contact_page", pathPattern: /^\/(contact|book|get-started)/ }],
43
43
  },
44
44
  },
45
45
  manual: {
@@ -48,7 +48,7 @@ export const { TrackingProvider, useTracking } = createTracking({
48
48
  cta_click: {},
49
49
  },
50
50
  },
51
- debug: process.env.NODE_ENV !== 'production',
51
+ debug: process.env.NODE_ENV !== "production",
52
52
  });
53
53
  ```
54
54
 
@@ -56,8 +56,8 @@ Wrap the root layout.
56
56
 
57
57
  ```tsx
58
58
  // app/layout.tsx
59
- import { ConsentBanner, GoogleAdsTracking } from '@aranova/tracking-next';
60
- import { TrackingProvider } from '@/lib/tracking';
59
+ import { ConsentBanner, GoogleAdsTracking } from "@aranova/tracking-next";
60
+ import { TrackingProvider } from "@/lib/tracking";
61
61
 
62
62
  export default function RootLayout({ children }: { children: React.ReactNode }) {
63
63
  return (
@@ -85,7 +85,7 @@ account plus a test MCC. Each entry fires `gtag('config', …)` on every page; t
85
85
  the dashboard's SDK table. Pass `environment` to the factory to tag events for dashboard filtering.
86
86
 
87
87
  ```tsx
88
- <GoogleAdsTracking gtagIds={{ production: 'AW-111111111', test: 'AW-222222222' }} />
88
+ <GoogleAdsTracking gtagIds={{ production: "AW-111111111", test: "AW-222222222" }} />
89
89
  ```
90
90
 
91
91
  ## Manual Events
@@ -93,9 +93,9 @@ the dashboard's SDK table. Pass `environment` to the factory to tag events for d
93
93
  Import `useTracking` from your local `lib/tracking` module, not directly from the package.
94
94
 
95
95
  ```tsx
96
- 'use client';
96
+ "use client";
97
97
 
98
- import { useTracking } from '@/lib/tracking';
98
+ import { useTracking } from "@/lib/tracking";
99
99
 
100
100
  export function LeadForm() {
101
101
  const tracking = useTracking();
@@ -108,22 +108,22 @@ export function LeadForm() {
108
108
  const form = event.currentTarget;
109
109
  const data = new FormData(form);
110
110
 
111
- tracking.trackEvent('form_submit', {
111
+ tracking.trackEvent("form_submit", {
112
112
  form: {
113
113
  id: form.id,
114
- action: form.getAttribute('action'),
114
+ action: form.getAttribute("action"),
115
115
  fields: [
116
116
  {
117
- name: 'service_interest',
118
- type: 'select',
119
- label: 'Service interest',
120
- value: String(data.get('service_interest') ?? ''),
117
+ name: "service_interest",
118
+ type: "select",
119
+ label: "Service interest",
120
+ value: String(data.get("service_interest") ?? ""),
121
121
  },
122
122
  {
123
- name: 'is_existing_patient',
124
- type: 'checkbox',
125
- label: 'Existing patient',
126
- value: data.get('is_existing_patient') === 'on',
123
+ name: "is_existing_patient",
124
+ type: "checkbox",
125
+ label: "Existing patient",
126
+ value: data.get("is_existing_patient") === "on",
127
127
  },
128
128
  ],
129
129
  },
@@ -145,11 +145,11 @@ Bundled `libphonenumber-js`: parse/format utils + a React input. Display is conf
145
145
  value sent to the backend is **always E.164**. Configure once via `createTracking({ phone: { defaultCountry: 'CA', display: 'national' } })`.
146
146
 
147
147
  ```tsx
148
- 'use client';
149
- import { usePhoneField, PhoneField, toE164 } from '@aranova/tracking-next';
148
+ "use client";
149
+ import { usePhoneField, PhoneField, toE164 } from "@aranova/tracking-next";
150
150
 
151
- const phone = usePhoneField(); // phone.value (display), phone.e164 (wire), .isValid, .error
152
- <input {...phone.inputProps} />; // or the batteries-included <PhoneField name="phone" />
151
+ const phone = usePhoneField(); // phone.value (display), phone.e164 (wire), .isValid, .error
152
+ <input {...phone.inputProps} />; // or the batteries-included <PhoneField name="phone" />
153
153
  ```
154
154
 
155
155
  Pure, isomorphic utils (usable in Server Components / route handlers) are at
@@ -161,11 +161,11 @@ Pure, isomorphic utils (usable in Server Components / route handlers) are at
161
161
  Read attribution cookies from Server Components or server actions.
162
162
 
163
163
  ```tsx
164
- import { getTrackingParamsServer } from '@aranova/tracking-next/server';
164
+ import { getTrackingParamsServer } from "@aranova/tracking-next/server";
165
165
 
166
166
  export default function Page() {
167
167
  const { gclid, utm_source } = getTrackingParamsServer();
168
- return gclid || utm_source === 'google' ? <GoogleLanding /> : <OrganicLanding />;
168
+ return gclid || utm_source === "google" ? <GoogleLanding /> : <OrganicLanding />;
169
169
  }
170
170
  ```
171
171
 
@@ -179,30 +179,39 @@ key may do is enforced by the backend, not by hiding methods. Browser write with
179
179
  your **public** key, from a client component:
180
180
 
181
181
  ```tsx
182
- 'use client';
183
- import { createSalesClient, toMinor } from '@aranova/tracking-next';
182
+ "use client";
183
+ import { createSalesClient, toMinor } from "@aranova/tracking-next";
184
184
 
185
- const sales = createSalesClient({ apiKey: process.env.NEXT_PUBLIC_ARANOVA_TRACKING_API_KEY!, endpoint });
186
- await sales.record({ currency: 'CAD', amount_total_cents: toMinor(250, 'CAD'), service: 'tires' });
185
+ const sales = createSalesClient({
186
+ apiKey: process.env.NEXT_PUBLIC_ARANOVA_TRACKING_API_KEY!,
187
+ endpoint,
188
+ });
189
+ await sales.record({ currency: "CAD", amount_total_cents: toMinor(250, "CAD"), service: "tires" });
187
190
  ```
188
191
 
189
- Full CRUD from a route handler / server action with your **secret** key (same
190
- import — keep the secret key in server env, never in client code):
192
+ Full CRUD from a route handler / server action / **Server Component** with your
193
+ **secret** key. Import from the **`/sales`** subpath — it's React-free, so it loads
194
+ in an RSC or any server module without dragging the provider/components into the
195
+ server graph (keep the secret key in server env, never in client code):
191
196
 
192
197
  ```ts
193
- import { createSalesClient } from '@aranova/tracking-next';
194
- import type { AranovaService } from './aranova-services'; // generated, see below
198
+ import { createSalesClient } from "@aranova/tracking-next/sales";
199
+ import type { AranovaService } from "./aranova-services"; // generated, see below
195
200
 
196
201
  const sales = createSalesClient<AranovaService>({
197
202
  apiKey: process.env.ARANOVA_TRACKING_SECRET_KEY!,
198
203
  endpoint: process.env.ARANOVA_TRACKING_ENDPOINT!,
199
204
  });
200
- await sales.list({ sort: 'amount_total_cents', want_total: true }); // → { items, total_count, … }
201
- await sales.summary({ range: 'mtd', timezone: 'America/Toronto', compare_to: 'previous_period' });
202
- await sales.customers.list({ segment: 'returning', sort: 'total_spent' }); // phone-keyed roster
203
- const cfg = await sales.business.config(); // tz / currencies / services
205
+ await sales.list({ sort: "amount_total_cents", want_total: true }); // → { items, total_count, … }
206
+ await sales.summary({ range: "mtd", timezone: "America/Toronto", compare_to: "previous_period" });
207
+ await sales.customers.list({ segment: "returning", sort: "total_spent" }); // phone-keyed roster
208
+ const cfg = await sales.business.config(); // tz / currencies / services
204
209
  ```
205
210
 
211
+ The root entry (`@aranova/tracking-next`) still re-exports `createSalesClient` and the
212
+ money/date helpers for back-compat, so existing imports keep working — but prefer
213
+ `/sales` in server code so the React surface never reaches your server bundle.
214
+
206
215
  Dashboard reads are all currency-grouped (never summed). `summary()` gains tz-aware calendar/custom
207
216
  ranges, `granularity`, and period-over-period `compare_to` (legacy `24h/7d/30d` unchanged); a
208
217
  **customer is their phone (E.164)**, so `customers.*` is a live roster with no separate table.
@@ -224,10 +233,10 @@ and the CLI reference: [cli.md](https://github.com/AranovaIO/aranova_internal/bl
224
233
  The bundled `<ConsentBanner />` renders a non-blocking bottom-docked banner while consent is `pending`, persists the visitor's choice to `localStorage`, and propagates it to Google Consent Mode v2 when gtag is loaded. **Inline-styled** — no Tailwind or CSS imports required at the consumer.
225
234
 
226
235
  ```tsx
227
- import { ConsentBanner } from '@aranova/tracking-next';
236
+ import { ConsentBanner } from "@aranova/tracking-next";
228
237
 
229
238
  // Drop-in (already wired in the root layout example above)
230
- <ConsentBanner />
239
+ <ConsentBanner />;
231
240
  ```
232
241
 
233
242
  All props are optional:
@@ -239,13 +248,13 @@ All props are optional:
239
248
  acceptLabel="Sure"
240
249
  declineLabel="No thanks"
241
250
  policyHref="/privacy"
242
- policyLabel="Privacy policy" // default: "Learn more"
243
- onAccept={() => track('consent_accepted')}
244
- onDecline={() => track('consent_declined')}
245
- position="bottom" // or "top"
246
- theme="light" // "light" | "dark" | "auto"
251
+ policyLabel="Privacy policy" // default: "Learn more"
252
+ onAccept={() => track("consent_accepted")}
253
+ onDecline={() => track("consent_declined")}
254
+ position="bottom" // or "top"
255
+ theme="light" // "light" | "dark" | "auto"
247
256
  className="my-extra-classes"
248
- style={{ background: '#fafafa' }} // wins over the theme defaults
257
+ style={{ background: "#fafafa" }} // wins over the theme defaults
249
258
  />
250
259
  ```
251
260
 
@@ -254,8 +263,8 @@ All props are optional:
254
263
  For a bespoke banner, skip the component and drive your own UI with the headless hook:
255
264
 
256
265
  ```tsx
257
- 'use client';
258
- import { useConsent } from '@aranova/tracking-next';
266
+ "use client";
267
+ import { useConsent } from "@aranova/tracking-next";
259
268
 
260
269
  function CookieBar() {
261
270
  const { state, accept, decline, reset, isPending } = useConsent();
@@ -278,8 +287,8 @@ The hook handles localStorage persistence, gtag sync, and cross-tab propagation
278
287
  ## Exports
279
288
 
280
289
  - Root package: `createTracking`, `TrackingProvider`, `useTracking`, `GoogleAdsTracking`, `ConsentBanner` (+ `ConsentBannerProps`), consent hooks/helpers, attribution hooks, event types; `createSalesClient()` (isomorphic — public key writes; secret key reads/CRUD, `summary`, `customers.*`, `business.config`) + `toMinor`/`fromMinor`/`formatMoney`/`formatDateInTz`; phone (`parsePhone`/`toE164`/`formatPhone`/`phoneField`, `usePhoneField`, `PhoneField`)
290
+ - `@aranova/tracking-next/sales`: **React-free** server-safe SDK — `createSalesClient`, money/date helpers, and all sale/customer/config types. Use this in Server Components, route handlers, and Node servers; the root entry re-exports the same symbols for back-compat.
281
291
  - `@aranova/tracking-next/middleware`: `createTrackingMiddleware()`
282
292
  - `@aranova/tracking-next/server`: `getTrackingParamsServer()`
283
293
  - `@aranova/tracking-next/phone`: isomorphic phone utils (no React)
284
294
  - Codegen: [`@aranova/tracking-cli`](https://www.npmjs.com/package/@aranova/tracking-cli) — `gen` typed service unions (devDependency)
285
-