@01.software/sdk 0.41.1 → 0.42.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/CHANGELOG.md +208 -0
- package/README.md +81 -18
- package/dist/analytics/react.cjs +71 -3
- package/dist/analytics/react.cjs.map +1 -1
- package/dist/analytics/react.d.cts +18 -2
- package/dist/analytics/react.d.ts +18 -2
- package/dist/analytics/react.js +67 -3
- package/dist/analytics/react.js.map +1 -1
- package/dist/analytics.cjs +6 -2
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.d.cts +17 -4
- package/dist/analytics.d.ts +17 -4
- package/dist/analytics.js +6 -2
- package/dist/analytics.js.map +1 -1
- package/dist/client.cjs +176 -32
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -6
- package/dist/client.d.ts +6 -6
- package/dist/client.js +176 -32
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-Bk--pNzW.d.cts → collection-client-B-qVIBnJ.d.cts} +3 -3
- package/dist/{collection-client-BdcxkW7l.d.ts → collection-client-BhCMwIus.d.ts} +3 -3
- package/dist/{const-qGGI7Uii.d.cts → const-BiDujixF.d.cts} +1 -1
- package/dist/{const-HwdntWtG.d.ts → const-pmHlwm3E.d.ts} +1 -1
- package/dist/{index-B1oW50RY.d.ts → index-B1UBDaKz.d.ts} +3 -3
- package/dist/{index-DiXtjVab.d.cts → index-D78ki6Ij.d.cts} +3 -3
- package/dist/index.cjs +156 -339
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +156 -339
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-CqJOgON7.d.cts → payload-types-C7Ul4ElL.d.cts} +181 -115
- package/dist/{payload-types-CqJOgON7.d.ts → payload-types-C7Ul4ElL.d.ts} +181 -115
- package/dist/query.d.cts +5 -5
- package/dist/query.d.ts +5 -5
- package/dist/realtime.cjs +1 -1
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js +1 -1
- package/dist/realtime.js.map +1 -1
- package/dist/server.cjs +230 -46
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +7 -7
- package/dist/server.d.ts +7 -7
- package/dist/server.js +230 -46
- package/dist/server.js.map +1 -1
- package/dist/{types-DgfXb7iV.d.ts → types-BL7M-EUV.d.cts} +138 -13
- package/dist/{types-BMI3M0nb.d.ts → types-Bf2iCjy8.d.ts} +1 -1
- package/dist/{types-ByLSG-O3.d.cts → types-ChV1t4ei.d.cts} +1 -1
- package/dist/{types-BKa9z9s2.d.cts → types-D5dSNIGs.d.ts} +138 -13
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +4 -4
- package/dist/webhook.d.ts +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,213 @@
|
|
|
1
1
|
# @01.software/sdk
|
|
2
2
|
|
|
3
|
+
## 0.42.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9cb8a41: Expose `commerce.cart.merge` and `commerce.cart.mine` on the public browser and
|
|
8
|
+
server commerce clients. `cart.merge({ guestCartToken })` unions or claims a
|
|
9
|
+
pre-login guest cart into the authenticated customer's cart; `cart.mine()` loads
|
|
10
|
+
the customer's active cart by JWT. Both return the resolved cart's `cartToken`
|
|
11
|
+
capability handle so a storefront can persist it and keep operating the cart by
|
|
12
|
+
token. The underlying endpoints and contract types already shipped; this binds
|
|
13
|
+
them into the `commerce.cart` namespace.
|
|
14
|
+
- a36d724: feat(sdk): add customer cart merge API
|
|
15
|
+
|
|
16
|
+
Adds `commerce.cart.merge({ guestCartToken })` for customer-authenticated
|
|
17
|
+
guest-cart claim or union merge flows. The method calls the new Console
|
|
18
|
+
`POST /api/carts/merge` endpoint and returns the merged customer cart plus merge
|
|
19
|
+
metadata so storefronts can replace their pre-login guest cart handle after
|
|
20
|
+
login.
|
|
21
|
+
|
|
22
|
+
- 426c3ed: feat(sdk): add customer cart resolution by JWT and merge cart handle
|
|
23
|
+
|
|
24
|
+
Adds `commerce.cart.mine()` for resolving the authenticated customer's active
|
|
25
|
+
cart (and its `cartToken` capability handle) by JWT alone, via the new Console
|
|
26
|
+
`POST /api/carts/mine` endpoint, so a storefront can load and operate a
|
|
27
|
+
customer's server cart on any device. `commerce.cart.merge` now also returns the
|
|
28
|
+
resolved customer cart's `cartToken`, so a post-login union into a different cart
|
|
29
|
+
row stays operable.
|
|
30
|
+
|
|
31
|
+
- a2fd60b: feat(sdk): root-export `Transaction` and `TransactionStatus` types
|
|
32
|
+
|
|
33
|
+
The payload `Transaction` type is now root-exported from `@01.software/sdk`, and
|
|
34
|
+
the hand-written `TransactionStatus` (which already includes `refunded`, aligned
|
|
35
|
+
with the payload `Transaction.status` enum) is exposed from the root entry too.
|
|
36
|
+
Storefront consumers can drop local `*Like` mirrors and `as unknown as` casts at
|
|
37
|
+
the SDK transaction boundary and import the real SDK types instead (#1539).
|
|
38
|
+
|
|
39
|
+
- 27a6502: feat(sdk): allow create-order requests without a shipping address
|
|
40
|
+
|
|
41
|
+
Digital, service, and other non-shipping orders can now be created without
|
|
42
|
+
`shippingAddress`. The create-order request type matches the Console contract
|
|
43
|
+
for variants that do not require parcel fulfillment.
|
|
44
|
+
|
|
45
|
+
- 5aa136f: feat(sdk): expose order `cancelReasonCode` (Shopify `OrderCancelReason` parity)
|
|
46
|
+
|
|
47
|
+
Canceled orders now persist the structured cancel reason as a first-class enum
|
|
48
|
+
(`customer` / `inventory` / `fraud` / `declined` / `staff` / `other`), mirroring
|
|
49
|
+
Shopify's `Order.cancelReason`. The generated `Order.cancelReasonCode` type gains
|
|
50
|
+
the field so consumers can read or filter cancellations by code. The free-text
|
|
51
|
+
`cancelReason` is retained for operator detail.
|
|
52
|
+
|
|
53
|
+
- 87da012: feat(sdk): expose order `currentTotalAmount` (Shopify `currentTotalPrice` parity)
|
|
54
|
+
|
|
55
|
+
Orders now surface a derived net total after refunds —
|
|
56
|
+
`currentTotalAmount = max(0, totalAmount - refundedAmount)` — mirroring
|
|
57
|
+
Shopify's `Order.currentTotalPrice`. The `PublicOrder` read type gains the
|
|
58
|
+
field so consumers can read the post-refund net as a single source of truth
|
|
59
|
+
instead of recomputing the subtraction. It is derived on read (not stored), so
|
|
60
|
+
existing `totalAmount` / `refundedAmount` fields are unchanged.
|
|
61
|
+
|
|
62
|
+
- 3f261a6: feat(sdk): add `partially_fulfilled` to order `displayFulfillmentStatus`
|
|
63
|
+
|
|
64
|
+
The order fulfillment display axis can now return `partially_fulfilled`, the
|
|
65
|
+
Shopify-parity value for a multi-line order whose ordered quantity is only
|
|
66
|
+
partially fulfilled. The generated `Order.displayFulfillmentStatus` type gains
|
|
67
|
+
the value, so consumers reading or branching on this field should handle it
|
|
68
|
+
(it sits between `on_hold` and `shipped`).
|
|
69
|
+
|
|
70
|
+
- 17afb8e: feat(sdk): orders `getByPaymentId` + `confirmPaymentReturningOrder` (#1540)
|
|
71
|
+
|
|
72
|
+
`server.commerce.orders.getByPaymentId({ pgProvider, pgPaymentId })` resolves the
|
|
73
|
+
depth-populated `{ order, transaction }` by PG payment id through the new sk-only
|
|
74
|
+
`GET /api/orders/by-payment` Console read (tenant-scoped, standard endpoint error
|
|
75
|
+
shape). Storefronts use it instead of raw
|
|
76
|
+
`transactions.find({ where: { pgPaymentId } })` plus a local order index, which
|
|
77
|
+
breaks on serverless.
|
|
78
|
+
|
|
79
|
+
`server.commerce.orders.confirmPaymentReturningOrder({ /* confirmPayment params */ })`
|
|
80
|
+
composes `confirmPayment` + `getByPaymentId`, returning
|
|
81
|
+
`{ ...confirmation, order, transaction }` so callers receive the populated
|
|
82
|
+
`Order` in one call. `confirmPayment`'s own wire response is unchanged
|
|
83
|
+
(IDs-only — its contract stays `.strict()`).
|
|
84
|
+
|
|
85
|
+
New exported types: `GetOrderByPaymentIdParams`, `OrderByPaymentResult`,
|
|
86
|
+
`ConfirmPaymentWithOrderResult`.
|
|
87
|
+
|
|
88
|
+
- a968dfd: refactor(sdk): keep server-only commerce API classes off the browser-safe root entry
|
|
89
|
+
|
|
90
|
+
The secret-key API classes `OrderApi`, `ProductApi`, `DiscountApi`, `ShippingApi`
|
|
91
|
+
(and the abstract `BaseApi`) are no longer runtime value exports on the root
|
|
92
|
+
`@01.software/sdk` entry — they are now re-exported as **type-only**. These classes
|
|
93
|
+
require a `secretKey` and throw at construction without one, so they belong behind the
|
|
94
|
+
server entry. Import the runtime surface from `@01.software/sdk/server`
|
|
95
|
+
(`ServerCommerceClient`) instead of constructing the low-level classes from root.
|
|
96
|
+
`import type { OrderApi } from '@01.software/sdk'` continues to work. The browser-safe
|
|
97
|
+
`CartApi` and the product-upsert helpers remain available at the root. This aligns the
|
|
98
|
+
root surface with ADR 0011 and is enforced at publish time by the root-import guard.
|
|
99
|
+
|
|
100
|
+
- 923b0a2: feat(sdk): typed analytics events + useAnalytics() React hook
|
|
101
|
+
|
|
102
|
+
`createAnalytics<TEvents>()` and the `defineAnalyticsEvents()` binder accept an
|
|
103
|
+
optional developer-declared event map (`AnalyticsEventMap` / `AnalyticsEventProps`)
|
|
104
|
+
so registered event names, dimensions, and enum values are checked at compile
|
|
105
|
+
time; the untyped `track(name, props?)` path is unchanged. New
|
|
106
|
+
`@01.software/sdk/analytics/react` exports — `AnalyticsProvider`,
|
|
107
|
+
`useAnalytics()` (`{ track, pageview }`), and `createAnalyticsHooks()` — let
|
|
108
|
+
components fire custom events; the existing `<Analytics/>` component is
|
|
109
|
+
unchanged. The hosted analytics snippet gains the same 3-state `mode`
|
|
110
|
+
(`captureOnLocalhost` retained as an alias).
|
|
111
|
+
</content>
|
|
112
|
+
|
|
113
|
+
- 2986732: feat(sdk): expose variant `inventoryPolicy` and treat `continue` as available for sale
|
|
114
|
+
|
|
115
|
+
Product variants now carry a Shopify-parity `inventoryPolicy` (`deny` default /
|
|
116
|
+
`continue`). A `continue` variant keeps tracking stock but stays purchasable past
|
|
117
|
+
available stock (backorder). The field is added to `ProductDetailVariant`,
|
|
118
|
+
`StockSnapshotItem`, and the `VariantInput` upsert contract, and
|
|
119
|
+
`getVariantAvailableForSale()` now returns `true` for an active `continue`
|
|
120
|
+
variant at zero stock. `getVariantAvailableStock()` is unchanged — it still
|
|
121
|
+
reports the real clamped quantity, mirroring Shopify `quantityAvailable`.
|
|
122
|
+
|
|
123
|
+
- 8ded73e: Storefront carts are now addressed by an unguessable Shopify-style `cartToken`
|
|
124
|
+
handle instead of the enumerable cart id (cart authorization fix, #1308).
|
|
125
|
+
|
|
126
|
+
Breaking changes:
|
|
127
|
+
- `commerce.cart.*` (and `CartApi`): the cart handle is now `cartToken`, not
|
|
128
|
+
`cartId`. `addItem`/`updateItem`/`removeItem`/`applyDiscount`/`removeDiscount`/
|
|
129
|
+
`clear` take `cartToken` (item ops still take `cartItemId`); `get(cartToken)`
|
|
130
|
+
now POSTs `/api/carts/get` with the token in the body.
|
|
131
|
+
- New `commerce.cart.create()` returns the `cartToken` (exposed only here —
|
|
132
|
+
persist it and pass it on every later call).
|
|
133
|
+
- `CartApi` no longer requires a secret key or customer token to construct; a
|
|
134
|
+
publishable key alone is a valid (guest) credential.
|
|
135
|
+
- CLI `cart` commands address carts by token (`01 cart add <cartToken> …`,
|
|
136
|
+
`update`/`remove` take `--cart-token`); new `01 cart create`.
|
|
137
|
+
|
|
138
|
+
`orders.checkout` is unchanged (still takes `cartId`) and may pass the optional
|
|
139
|
+
`cartToken` for defense in depth.
|
|
140
|
+
|
|
141
|
+
### Patch Changes
|
|
142
|
+
|
|
143
|
+
- b011902: fix(sdk): sync generated analytics drop reason payload types
|
|
144
|
+
|
|
145
|
+
The generated Payload types now include schema drop reason breakdown fields on
|
|
146
|
+
`tenant-analytics-daily.eventsDropped`: unknown event, unknown dimension, bad
|
|
147
|
+
value, and invalid props shape. The existing aggregate `schema` count remains
|
|
148
|
+
available for compatibility.
|
|
149
|
+
|
|
150
|
+
- 9d1b632: Move SDK API URL resolution into the internal HTTP utility layer so runtime code no longer imports URL resolution from the client type definitions module.
|
|
151
|
+
- d28ad57: chore(sdk): add canvasRevision to generated Canvas type
|
|
152
|
+
|
|
153
|
+
The Canvas collection gained a server-managed `canvasRevision`
|
|
154
|
+
optimistic-concurrency token (Console #1473). The SDK's generated payload types
|
|
155
|
+
now include the optional `canvasRevision?: string | null` field on `Canvas`.
|
|
156
|
+
Type-only change — no SDK runtime, request shape, or public API change.
|
|
157
|
+
|
|
158
|
+
- 9261a15: chore(sdk): add cart shipping-authority fields to generated Cart type
|
|
159
|
+
|
|
160
|
+
The Cart collection gained a `shippingPolicy` relationship and an internal
|
|
161
|
+
`freeShippingDiscount` flag so the cart computes and stores its own shipping
|
|
162
|
+
(Console #1541 / Y2). The SDK's generated payload types now include the optional
|
|
163
|
+
`shippingPolicy?` and `freeShippingDiscount?` fields on `Cart`. Type-only change
|
|
164
|
+
— no SDK runtime, request shape, or public API change.
|
|
165
|
+
|
|
166
|
+
- 8d8e700: feat(sdk): sync tenant commerce notification branded-sender types
|
|
167
|
+
|
|
168
|
+
The generated Payload types now include optional
|
|
169
|
+
`tenant.commerceNotifications.senderDisplayName` and `senderReplyTo` fields,
|
|
170
|
+
backing the Phase 0 branded fallback sender (display name + Reply-To over the
|
|
171
|
+
verified platform send-from address). Existing tenant fields are unchanged.
|
|
172
|
+
|
|
173
|
+
- 9f3186c: docs(sdk): document carrier/trackingNumber pairing on createFulfillment
|
|
174
|
+
|
|
175
|
+
`createFulfillment` requires `carrier` and `trackingNumber` to be sent together
|
|
176
|
+
(both for a carrier-facing shipment, or neither for a manual handoff). The
|
|
177
|
+
`CreateFulfillmentParams` type doc now states this; a half-pair is rejected
|
|
178
|
+
server-side with `400 validation_failed`. No request-shape change.
|
|
179
|
+
|
|
180
|
+
- b1bdd49: Generated `payload-types.ts` field-description JSDoc comments were trimmed to
|
|
181
|
+
short, neutral operator copy (Console field-description cleanup, #1501). This is
|
|
182
|
+
a documentation-only change to the generated type comments — no field names,
|
|
183
|
+
types, or API shapes change.
|
|
184
|
+
- e3b16a5: Generated `payload-types.ts` field-description JSDoc comments inherited from the
|
|
185
|
+
shared field factories (image alt, taxonomy image/color, SEO Open Graph image,
|
|
186
|
+
feature-gated videos) were trimmed to short, neutral operator copy (#1502). This
|
|
187
|
+
is a documentation-only change to the generated type comments — no field names,
|
|
188
|
+
types, or API shapes change.
|
|
189
|
+
- 4a13b7b: feat(sdk): sync tenant verified sender-domain types
|
|
190
|
+
|
|
191
|
+
The generated Payload types now include optional
|
|
192
|
+
`tenant.commerceNotifications` fields backing the Phase 1 verified sender domain:
|
|
193
|
+
`senderDomain`, `senderLocalpart`, and the server-managed `senderDomainStatus`,
|
|
194
|
+
`senderDomainResendId`, and `senderDomainRecords`. Commerce notifications send
|
|
195
|
+
from the tenant's own domain only once it is verified, otherwise the Phase 0 /
|
|
196
|
+
platform sender is used. Existing tenant fields are unchanged.
|
|
197
|
+
|
|
198
|
+
- 1d8ee45: fix(sdk): correct transport error/path contract
|
|
199
|
+
- Real HTTP `429` responses now map to `RateLimitError` (with `Retry-After`
|
|
200
|
+
parsed into `retryAfter`) instead of `NetworkError`, and are no longer retried
|
|
201
|
+
with plain exponential backoff. Usage-quota `429` (with `X-Usage-*` headers)
|
|
202
|
+
still maps to `UsageLimitError`.
|
|
203
|
+
- `410` now maps to `GoneError` and `503` to `ServiceUnavailableError` (with
|
|
204
|
+
`Retry-After`), making the previously-unreachable `isGoneError` /
|
|
205
|
+
`isServiceUnavailableError` guards usable. HTTP-status → typed-error mapping is
|
|
206
|
+
consolidated into a single function.
|
|
207
|
+
- Commerce request paths are consolidated into one internal `COMMERCE_ENDPOINTS`
|
|
208
|
+
map, guarded by a parity test against the Console endpoint registration so a
|
|
209
|
+
path change can no longer silently become a runtime 404.
|
|
210
|
+
|
|
3
211
|
## 0.41.1
|
|
4
212
|
|
|
5
213
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -24,23 +24,6 @@ pnpm add @01.software/sdk
|
|
|
24
24
|
|
|
25
25
|
### Sub-path Imports
|
|
26
26
|
|
|
27
|
-
```typescript
|
|
28
|
-
// Analytics — browser pageview tracking + custom events
|
|
29
|
-
import { createAnalytics } from '@01.software/sdk/analytics'
|
|
30
|
-
const analytics = createAnalytics({ publishableKey: 'pk_xxx' })
|
|
31
|
-
// auto-tracks pageviews; call analytics.pageview('/custom-path') manually if needed
|
|
32
|
-
analytics.track('signup', { plan: 'pro', trial: false }) // custom event with optional props
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
```tsx
|
|
36
|
-
// Analytics React component — Vercel Analytics-style mount helper
|
|
37
|
-
import { Analytics } from '@01.software/sdk/analytics/react'
|
|
38
|
-
|
|
39
|
-
export function App() {
|
|
40
|
-
return <Analytics />
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
27
|
```typescript
|
|
45
28
|
// Main entry - browser client, query builder, commerce helpers, utilities
|
|
46
29
|
import { createClient } from '@01.software/sdk'
|
|
@@ -112,6 +95,86 @@ Migration quick reference:
|
|
|
112
95
|
self-contained and must not import private contracts; Console code should
|
|
113
96
|
import shared helpers from contracts directly.
|
|
114
97
|
|
|
98
|
+
### Analytics
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Pageviews + custom events (browser)
|
|
102
|
+
import { createAnalytics } from '@01.software/sdk/analytics'
|
|
103
|
+
|
|
104
|
+
const analytics = createAnalytics({ publishableKey: 'pk_xxx' })
|
|
105
|
+
// auto-tracks pageviews; call analytics.pageview('/custom-path') manually if needed
|
|
106
|
+
analytics.track('signup', { plan: 'pro', trial: false })
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Custom events must be registered first.** Each custom event name, its
|
|
110
|
+
dimensions, and any enum/boolean value sets are defined per workspace in
|
|
111
|
+
Console → Analytics. An unregistered or mistyped event is accepted by the
|
|
112
|
+
browser (200/204) and then **silently dropped server-side** — no client error.
|
|
113
|
+
Register the event before firing it.
|
|
114
|
+
|
|
115
|
+
**Typed events (compile-time safety).** Declare an event map as a plain `type`
|
|
116
|
+
(do **not** `extends AnalyticsEventMap` — an index signature would defeat
|
|
117
|
+
typo detection) and pass it as the generic. Mistyped names and out-of-enum
|
|
118
|
+
values then fail to compile:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { createAnalytics, defineAnalyticsEvents } from '@01.software/sdk/analytics'
|
|
122
|
+
|
|
123
|
+
type ShopEvents = {
|
|
124
|
+
signup: { plan: 'free' | 'pro'; trial: boolean }
|
|
125
|
+
add_to_cart: { productId: string; price: number }
|
|
126
|
+
checkout_start: undefined // no props
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const analytics = createAnalytics<ShopEvents>({ publishableKey: 'pk_xxx' })
|
|
130
|
+
analytics.track('signup', { plan: 'pro', trial: false }) // ✅
|
|
131
|
+
analytics.track('checkout_start') // ✅ no props
|
|
132
|
+
// analytics.track('signpu', { plan: 'pro', trial: false }) // ❌ unknown event
|
|
133
|
+
// analytics.track('signup', { plan: 'team', trial: false }) // ❌ enum violation
|
|
134
|
+
|
|
135
|
+
// Bind the map once to avoid repeating the generic:
|
|
136
|
+
const create = defineAnalyticsEvents<ShopEvents>()
|
|
137
|
+
const a2 = create({ publishableKey: 'pk_xxx' })
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**React.** Use `AnalyticsProvider` + `useAnalytics()` to fire events from
|
|
141
|
+
components. The provider auto-tracks pageviews like `<Analytics/>` and owns one
|
|
142
|
+
instance for its subtree:
|
|
143
|
+
|
|
144
|
+
Reusing the `ShopEvents` type from above:
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { AnalyticsProvider, useAnalytics } from '@01.software/sdk/analytics/react'
|
|
148
|
+
|
|
149
|
+
function Root() {
|
|
150
|
+
return (
|
|
151
|
+
<AnalyticsProvider>
|
|
152
|
+
<App />
|
|
153
|
+
</AnalyticsProvider>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function SignupButton() {
|
|
158
|
+
const { track, pageview } = useAnalytics<ShopEvents>()
|
|
159
|
+
// pageview(path?) is available for manual SPA pageviews; the provider already auto-tracks pageviews
|
|
160
|
+
return (
|
|
161
|
+
<button onClick={() => track('signup', { plan: 'pro', trial: false })}>
|
|
162
|
+
Sign up
|
|
163
|
+
</button>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`<Analytics />` remains available as a pageview-only mount helper for apps that
|
|
169
|
+
do not fire custom events from components.
|
|
170
|
+
|
|
171
|
+
**Send mode.** `mode: 'auto'` (default) suppresses sends on local hosts
|
|
172
|
+
(`localhost` / `127.0.0.1` / `*.local`); `'production'` always sends, even
|
|
173
|
+
locally; `'development'` never sends. The hosted `<script>` snippet uses the
|
|
174
|
+
same vocabulary via `window.__01_analytics__.mode` or `data-mode`; its legacy
|
|
175
|
+
`captureOnLocalhost: true` flag is equivalent to `mode: 'production'` and is
|
|
176
|
+
honored only when `mode` is unset.
|
|
177
|
+
|
|
115
178
|
## Getting Started
|
|
116
179
|
|
|
117
180
|
### Client
|
|
@@ -1343,7 +1406,7 @@ join-order surface and does not emit a semantic order-change webhook.
|
|
|
1343
1406
|
|
|
1344
1407
|
## Supported Collections
|
|
1345
1408
|
|
|
1346
|
-
Source of truth: `packages/sdk/src/core/collection/const.ts` (`COLLECTIONS
|
|
1409
|
+
Source of truth: `packages/sdk/src/core/collection/const.ts` (`COLLECTIONS`).
|
|
1347
1410
|
|
|
1348
1411
|
| Category | Browser-public generic collections |
|
|
1349
1412
|
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
package/dist/analytics/react.cjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,18 +18,29 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
|
|
21
31
|
// src/analytics/react.tsx
|
|
22
32
|
var react_exports = {};
|
|
23
33
|
__export(react_exports, {
|
|
24
34
|
Analytics: () => Analytics,
|
|
25
|
-
|
|
35
|
+
AnalyticsProvider: () => AnalyticsProvider,
|
|
36
|
+
createAnalyticsHooks: () => createAnalyticsHooks,
|
|
37
|
+
default: () => react_default,
|
|
38
|
+
useAnalytics: () => useAnalytics
|
|
26
39
|
});
|
|
27
40
|
module.exports = __toCommonJS(react_exports);
|
|
28
|
-
var import_react = require("react");
|
|
41
|
+
var import_react = __toESM(require("react"), 1);
|
|
29
42
|
|
|
30
|
-
// src/core/
|
|
43
|
+
// src/core/internal/utils/api-url.ts
|
|
31
44
|
function resolveApiUrl(apiUrl) {
|
|
32
45
|
if (apiUrl) {
|
|
33
46
|
return apiUrl.replace(/\/$/, "");
|
|
@@ -273,4 +286,59 @@ function Analytics({
|
|
|
273
286
|
return null;
|
|
274
287
|
}
|
|
275
288
|
var react_default = Analytics;
|
|
289
|
+
var AnalyticsContext = (0, import_react.createContext)(null);
|
|
290
|
+
var NOOP_ANALYTICS = {
|
|
291
|
+
track() {
|
|
292
|
+
},
|
|
293
|
+
pageview() {
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
function AnalyticsProvider({
|
|
297
|
+
autoTrack,
|
|
298
|
+
endpoint,
|
|
299
|
+
mode,
|
|
300
|
+
publishableKey,
|
|
301
|
+
respectDnt,
|
|
302
|
+
children
|
|
303
|
+
}) {
|
|
304
|
+
const instanceRef = (0, import_react.useRef)(null);
|
|
305
|
+
const [value, setValue] = (0, import_react.useState)(NOOP_ANALYTICS);
|
|
306
|
+
(0, import_react.useEffect)(() => {
|
|
307
|
+
const resolvedPublishableKey = resolveAnalyticsPublishableKey(publishableKey);
|
|
308
|
+
if (!resolvedPublishableKey) return;
|
|
309
|
+
const analytics = createAnalytics({
|
|
310
|
+
autoTrack,
|
|
311
|
+
endpoint,
|
|
312
|
+
mode,
|
|
313
|
+
publishableKey: resolvedPublishableKey,
|
|
314
|
+
respectDnt
|
|
315
|
+
});
|
|
316
|
+
instanceRef.current = analytics;
|
|
317
|
+
setValue({
|
|
318
|
+
track: (...args) => instanceRef.current?.track(...args),
|
|
319
|
+
pageview: (path) => instanceRef.current?.pageview(path)
|
|
320
|
+
});
|
|
321
|
+
return () => {
|
|
322
|
+
analytics.destroy();
|
|
323
|
+
instanceRef.current = null;
|
|
324
|
+
setValue(NOOP_ANALYTICS);
|
|
325
|
+
};
|
|
326
|
+
}, [autoTrack, endpoint, mode, publishableKey, respectDnt]);
|
|
327
|
+
return /* @__PURE__ */ import_react.default.createElement(AnalyticsContext.Provider, { value }, children);
|
|
328
|
+
}
|
|
329
|
+
function useAnalytics() {
|
|
330
|
+
const ctx = (0, import_react.useContext)(AnalyticsContext);
|
|
331
|
+
if (ctx === null) {
|
|
332
|
+
throw new Error(
|
|
333
|
+
"useAnalytics must be used within an <AnalyticsProvider>."
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
return ctx;
|
|
337
|
+
}
|
|
338
|
+
function createAnalyticsHooks() {
|
|
339
|
+
return {
|
|
340
|
+
AnalyticsProvider,
|
|
341
|
+
useAnalytics
|
|
342
|
+
};
|
|
343
|
+
}
|
|
276
344
|
//# sourceMappingURL=react.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/analytics/react.tsx","../../src/core/client/types.ts","../../src/analytics.ts","../../src/analytics/env.ts"],"sourcesContent":["'use client'\n\nimport { useEffect } from 'react'\nimport { createAnalytics, type AnalyticsConfig } from '../analytics'\nimport { resolveAnalyticsPublishableKey } from './env'\n\nexport type AnalyticsProps = Omit<AnalyticsConfig, 'publishableKey'> & {\n publishableKey?: string\n}\n\nexport function Analytics({\n autoTrack,\n endpoint,\n mode,\n publishableKey,\n respectDnt,\n}: AnalyticsProps) {\n useEffect(() => {\n const resolvedPublishableKey =\n resolveAnalyticsPublishableKey(publishableKey)\n if (!resolvedPublishableKey) return\n\n const analytics = createAnalytics({\n autoTrack,\n endpoint,\n mode,\n publishableKey: resolvedPublishableKey,\n respectDnt,\n })\n\n return () => analytics.destroy()\n }, [autoTrack, endpoint, mode, publishableKey, respectDnt])\n\n return null\n}\n\nexport default Analytics\n","import type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n} from '../collection/const'\nimport type { CollectionType } from '../collection/types'\nimport type { CommunityClient } from '../community/community-client'\nimport type {\n BanCustomerParams,\n CommunityBan,\n UnbanCustomerParams,\n} from '../community/moderation-api'\nimport type { CommerceClient } from '../commerce/commerce-client'\nimport type { ContentClient } from '../content/content-client'\nimport type { ServerCommerceClient } from '../commerce/server-commerce-client'\nimport type { CustomerNamespace } from '../customer/customer-namespace'\nimport type { EventsClient } from '../events/events-client'\nimport type { TenantIntrospectionClient } from '../api/tenant-introspection-api'\n\nexport type {\n Collection,\n PublicCollection,\n ServerCollection,\n ServerOnlyCollection,\n}\n\n// ============================================================================\n// API URL Configuration\n// ============================================================================\n\ndeclare const __DEFAULT_API_URL__: string\n\nexport function resolveApiUrl(apiUrl?: string): string {\n if (apiUrl) {\n return apiUrl.replace(/\\/$/, '')\n }\n\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n\n// ============================================================================\n// Client Configuration\n// ============================================================================\n\nexport interface ClientConfig {\n publishableKey: string\n /** API base URL for staging, self-hosted, preview, or proxy deployments. */\n apiUrl?: string\n /**\n * Customer authentication options.\n * Used to initialize CustomerAuth on Client.\n */\n customer?: {\n /**\n * Persist token in localStorage. Defaults to `true`.\n * - `true` (default): uses key `'customer-token'`\n * - `string`: uses the given string as localStorage key\n * - `false`: disables persistence (token/onTokenChange used instead)\n *\n * Handles SSR safely (no-op on server).\n * When enabled, `token` and `onTokenChange` are ignored.\n */\n persist?: boolean | string\n /** Initial token (e.g. from SSR cookie) */\n token?: string\n /** Called when token changes (login/logout) — use to persist in localStorage/cookie */\n onTokenChange?: (token: string | null) => void\n }\n}\n\n// Server client: requires both publishableKey (for CDN routing + rate limit +\n// monthly quota enforcement via the edge proxy) and secretKey (sk01_ opaque\n// bearer token, the authentication credential).\n// The proxy keys its tenant lookup off `X-Publishable-Key`, so omitting\n// publishableKey would silently bypass rate limiting and plan-based quota\n// enforcement.\nexport interface ClientServerConfig extends ClientConfig {\n secretKey: string\n}\n\nexport interface ClientMetadata {\n userAgent?: string\n timestamp: number\n}\n\nexport interface ClientState {\n metadata: ClientMetadata\n}\n\nexport interface PaginationMeta {\n page: number\n limit: number\n totalDocs: number\n totalPages: number\n hasNextPage: boolean\n hasPrevPage: boolean\n pagingCounter: number\n prevPage: number | null\n nextPage: number | null\n}\n\n// ============================================================================\n// Payload CMS Native Response Types\n// ============================================================================\n\n/**\n * Payload CMS Find (List) Response\n * GET /api/{collection}\n */\nexport interface PayloadFindResponse<T = unknown> {\n docs: T[]\n totalDocs: number\n limit: number\n totalPages: number\n page: number\n pagingCounter: number\n hasPrevPage: boolean\n hasNextPage: boolean\n prevPage: number | null\n nextPage: number | null\n}\n\n/**\n * Payload CMS Create/Update Response\n * POST /api/{collection}\n * PATCH /api/{collection}/{id}\n */\nexport interface PayloadMutationResponse<T = unknown> {\n message: string\n doc: T\n errors?: unknown[]\n}\n\n// ============================================================================\n// Query Options\n// ============================================================================\n\nexport type Sort = string | string[]\nexport type Where = Record<string, unknown>\n\n/**\n * Do NOT replace with `Pick<FindOptions>` from `payload` or import Payload\n * types here. Payload's generic query types depend on `PayloadTypes` module\n * augmentation; external SDK consumers who only use `createClient` should not\n * install Payload just to type REST query objects. Excluded vs native:\n * Local-API-only fields, `locale`/`fallbackLocale`.\n */\nexport interface ApiQueryOptions {\n page?: number\n limit?: number\n sort?: Sort\n /**\n * Filter documents. Id-based relation filters (`where: { product: { equals: id } }`) are the\n * most reliable pattern. Dotted-path relation filters (`where: { 'product.slug': { equals } }`)\n * are Payload-native but may silently return empty when access control restricts the related\n * document or when the relation is polymorphic. String shorthand (`where: { slug: 'x' }`)\n * silently matches nothing — always use `{ slug: { equals: 'x' } }`.\n */\n where?: Where\n /**\n * Controls how deeply relationship fields are populated. This is the primary control for\n * populating relationships like `category`, `images`, `brand`. The configured Payload default\n * applies when unset.\n */\n depth?: number\n select?: Record<string, boolean>\n /**\n * Controls which fields are returned for already-populated relationships, keyed by collection\n * slug. Does NOT control which relationships to populate — that is `depth`.\n *\n * @example\n * // depth: 2 populates category; populate trims which fields come back\n * populate: { categories: { title: true, slug: true } }\n */\n populate?: Record<string, boolean | Record<string, boolean>>\n /**\n * Controls Payload `type: 'join'` virtual reverse-relation fields only (pagination, sort,\n * filter, count per join field, or `false` to disable all join-field population).\n *\n * Does NOT populate normal relationship fields like `category`, `images`, or `brand`.\n * For normal relationship population use `depth` (and optionally `populate` for field\n * selection).\n *\n * Pass `joins: false` to disable all join-field population — useful for lightweight list\n * queries where join fields are not needed.\n *\n * @example\n * // `article-authors` has a `type: 'join'` field `articles` (reverse-relation)\n * joins: { articles: { limit: 10, sort: '-publishedAt' } }\n *\n * // depth: 2 populates product.category — joins has no effect on this\n * depth: 2\n *\n * // Disable all join-field population\n * joins: false\n */\n joins?:\n | Record<\n string,\n | {\n limit?: number\n page?: number\n sort?: string\n where?: Where\n count?: boolean\n }\n | false\n >\n | false\n /** Set to `false` to skip the count query — returns docs without totalDocs/totalPages */\n pagination?: boolean\n /** Include draft versions (access control still applies on the server) */\n draft?: boolean\n /** Include soft-deleted documents (requires `trash` enabled on the collection) */\n trash?: boolean\n}\n\nexport type ApiDeleteOptions = Pick<ApiQueryOptions, 'trash'>\n\nexport type PublicReadQueryOptions = Omit<\n ApiQueryOptions,\n 'depth' | 'joins' | 'populate'\n> & {\n /**\n * Publishable collection reads stay unpopulated. Use shaped commerce/community\n * endpoints or a server client when populated relations are required.\n */\n depth?: 0\n /**\n * Publishable collection reads disable Payload join fields to avoid accidental\n * exposure and expensive generic list responses.\n */\n joins?: false\n /** Publishable collection reads do not support relationship populate maps. */\n populate?: never\n}\n\n// ============================================================================\n// Debug & Retry Configuration\n// ============================================================================\n\nexport interface DebugConfig {\n logRequests?: boolean\n logResponses?: boolean\n logErrors?: boolean\n}\n\nexport interface RetryConfig {\n maxRetries?: number\n retryableStatuses?: number[]\n retryDelay?: (attempt: number) => number\n}\n\n// ============================================================================\n// Lightweight root entry contracts\n// ============================================================================\n\ninterface RootQueryLookup<\n T extends string,\n Options extends ApiQueryOptions = ApiQueryOptions,\n> {\n find(\n options?: Options,\n ): Promise<PayloadFindResponse<CollectionType<T>>>\n findById(\n id: string | number,\n options?: Options,\n ): Promise<CollectionType<T>>\n count(options?: Options): Promise<{ totalDocs: number }>\n}\n\nexport type RootReadOnlyQueryBuilder<T extends PublicCollection> =\n RootQueryLookup<T, PublicReadQueryOptions>\n\nexport interface RootServerQueryBuilder<\n T extends ServerCollection,\n> extends RootQueryLookup<T> {\n create(\n data: Partial<CollectionType<T>>,\n options?: { file?: File | Blob; filename?: string },\n ): Promise<PayloadMutationResponse<CollectionType<T>>>\n update(\n id: string,\n data: Partial<CollectionType<T>>,\n options?: { file?: File | Blob; filename?: string },\n ): Promise<PayloadMutationResponse<CollectionType<T>>>\n updateMany(\n where: ApiQueryOptions['where'],\n data: Partial<CollectionType<T>>,\n ): Promise<PayloadFindResponse<CollectionType<T>>>\n remove(id: string, options?: ApiDeleteOptions): Promise<CollectionType<T>>\n removeMany(\n where: ApiQueryOptions['where'],\n ): Promise<PayloadFindResponse<CollectionType<T>>>\n}\n\nexport interface RootCollectionClient {\n from<T extends PublicCollection>(collection: T): RootReadOnlyQueryBuilder<T>\n}\n\nexport interface RootServerCollectionClient {\n from<T extends ServerCollection>(collection: T): RootServerQueryBuilder<T>\n}\n\nexport interface RootClient {\n commerce: CommerceClient\n community: CommunityClient\n content: ContentClient\n /** Set on {@link createClient} return values; optional for structural mocks. */\n events?: EventsClient\n customer: CustomerNamespace\n collections: RootCollectionClient\n lastRequestId: string | null\n getState(): ClientState\n getConfig(): ClientConfig\n}\n\nexport interface RootServerClient {\n commerce: ServerCommerceClient\n tenant: TenantIntrospectionClient\n /** Set on {@link createServerClient} return values; optional for structural mocks. */\n events?: EventsClient\n community: CommunityClient & {\n moderation: {\n banCustomer: (p: BanCustomerParams) => Promise<CommunityBan>\n unbanCustomer: (p: UnbanCustomerParams) => Promise<{ success: true }>\n }\n }\n collections: RootServerCollectionClient\n lastRequestId: string | null\n getState(): ClientState\n getConfig(): Omit<ClientServerConfig, 'secretKey'>\n}\n\nexport type RootClientWithEvents = RootClient & { events: EventsClient }\n\nexport type RootServerClientWithEvents = RootServerClient & { events: EventsClient }\n\n// ============================================================================\n// Type Utilities\n// ============================================================================\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]\n}\n\nexport type ExtractArrayType<T> = T extends (infer U)[] ? U : never\n","/**\n * @01.software/sdk — Analytics Helper\n */\n\n/* ANALYTICS INVARIANTS START\n * @01.software/sdk — Analytics Helper\n *\n * ANALYTICS INVARIANTS\n * ====================\n * These invariants are the single source of truth for observable behavior.\n * They are mirrored verbatim in apps/console/src/app/api/analytics/script.js/route.ts.\n * Any change here MUST be reflected there, and vice versa.\n *\n * 1. DNT/GPC respect: when config.respectDnt !== false (default true) AND\n * (navigator.doNotTrack === '1' OR navigator.globalPrivacyControl === true),\n * all methods become no-ops. Zero network requests are made.\n *\n * 2. Prerender skip: when document.prerendering === true OR\n * document.visibilityState === 'prerender', pageview() sends zero requests.\n *\n * 3. 500ms same-path dedup: a pageview for the same pathname within 500ms of\n * the previous send is silently dropped. After 500ms the next call sends.\n *\n * 4. Transport: sendBeacon → fetch keepalive fallback.\n * Primary: navigator.sendBeacon(endpoint, new Blob([json], { type: 'text/plain' })).\n * Fallback (sendBeacon unavailable OR returns false):\n * fetch(endpoint, { method: 'POST', keepalive: true,\n * headers: { 'Content-Type': 'application/json' }, body: json }).catch(() => {})\n *\n * 5. Body-only publishableKey: publishableKey is always in the request body,\n * never in any HTTP header.\n *\n * 6. SSR no-op: when typeof window === 'undefined', createAnalytics() returns\n * a stub where all methods are no-ops. No side effects occur.\n *\n * 7. Error swallowing: all transport errors are caught and swallowed.\n * createAnalytics() and all returned methods never throw into the caller.\n *\n * 8. Client timestamp: every send carries eventTs (milliseconds since epoch)\n * captured with Date.now() immediately before transport. The collect\n * endpoint uses eventTs (a) to bucket the event into the client's\n * tenant-local day and (b) to enforce the late-arrival cutoff; events\n * submitted after the local-day-end grace window are dropped with\n * reason \"late\".\n *\n * 9. Dev / local-host send skip: in 'auto' mode (the default) all send paths\n * become no-ops when the page runs on a local host — location.hostname is\n * 'localhost', '127.0.0.1', or ends with '.local'. Validation and dev\n * warnings still run; only the network send is suppressed, and a one-time\n * console notice is emitted. SSR (6), DNT/GPC (1), and prerender (2) skips\n * are evaluated first. Overrides: the SDK accepts mode 'production' (always\n * send, even locally) and 'development' (never send, on any host); the\n * mirrored hosted snippet accepts captureOnLocalhost === true (via\n * window.__01_analytics__.captureOnLocalhost or the script's\n * data-capture-localhost attribute) to force sending on a local host.\n * ANALYTICS INVARIANTS END */\n\nimport { resolveApiUrl } from './core/client/types'\n\n// ============================================================================\n// Public Types\n// ============================================================================\n\nexport interface AnalyticsConfig {\n publishableKey: string\n /** Override the collect endpoint URL. Defaults to {SDK_BASE_URL}/api/analytics/collect */\n endpoint?: string\n /** Auto-patch history.pushState/replaceState and listen to popstate. Default: true */\n autoTrack?: boolean\n /** Respect navigator.doNotTrack and navigator.globalPrivacyControl. Default: true */\n respectDnt?: boolean\n /**\n * Send mode. 'auto' (default) skips all sends on local hosts\n * (localhost / 127.0.0.1 / *.local). 'production' always sends, even\n * locally. 'development' never sends, on any host. See INVARIANT 9.\n */\n mode?: 'auto' | 'production' | 'development'\n}\n\nexport interface Analytics {\n pageview(path?: string): void\n track(name: string, props?: Record<string, string | number | boolean>): void\n destroy(): void\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n // INVARIANT 6: SSR no-op\n if (typeof window === 'undefined') {\n return { pageview() {}, track() {}, destroy() {} }\n }\n\n const endpoint =\n config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`\n\n // INVARIANT 1: DNT/GPC check (evaluated once at init; stays as closure)\n const respectDnt = config.respectDnt !== false\n function isDntActive(): boolean {\n if (!respectDnt) return false\n const nav = navigator as Navigator & { globalPrivacyControl?: boolean }\n return nav.doNotTrack === '1' || nav.globalPrivacyControl === true\n }\n\n // INVARIANT 9: local-host detection drives both dev warnings and the\n // auto send-skip. Hostname is the one signal shared with the hosted snippet.\n const isLocalHost: boolean = (() => {\n try {\n const h = location.hostname\n return h === 'localhost' || h === '127.0.0.1' || h.endsWith('.local')\n } catch {\n return false\n }\n })()\n\n const mode = config.mode ?? 'auto'\n const sendSuppressed =\n mode === 'development' || (mode === 'auto' && isLocalHost)\n\n let suppressNoticeShown = false\n function devSuppressNotice(): void {\n if (suppressNoticeShown) return\n suppressNoticeShown = true\n try {\n console.info(\n `[01 analytics] events disabled on local host (mode: '${mode}'). ` +\n `Pass mode: 'production' to send while developing.`,\n )\n } catch {\n // INVARIANT 7: swallow\n }\n }\n\n // INVARIANT 3: 500ms same-path dedup state\n let lastPath: string | null = null\n let lastAt = 0\n\n // autoTrack state — save originals for destroy()\n const autoTrack = config.autoTrack !== false\n const originalPushState = history.pushState\n const originalReplaceState = history.replaceState\n let destroyed = false\n\n // -------------------------------------------------------------------------\n // Core send logic\n // -------------------------------------------------------------------------\n\n // Generate a unique event ID (crypto.randomUUID when available, Date+Math.random fallback)\n function newEventId(): string {\n return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : String(Date.now()) + String(Math.random())\n }\n\n // INVARIANT 4: sendBeacon → fetch keepalive fallback\n // INVARIANT 5: publishableKey in body only\n function sendBeaconOrFetch(body: string): void {\n try {\n if (typeof navigator.sendBeacon === 'function') {\n const blob = new Blob([body], { type: 'text/plain' })\n const sent = navigator.sendBeacon(endpoint, blob)\n if (sent) return\n // sent === false → fall through to fetch\n }\n // Fetch fallback\n fetch(endpoint, {\n method: 'POST',\n keepalive: true,\n headers: { 'Content-Type': 'application/json' },\n body,\n }).catch(() => {})\n } catch {\n // INVARIANT 7: swallow all errors\n }\n }\n\n function sendPageview(pathname: string): void {\n // INVARIANT 1: DNT/GPC\n if (isDntActive()) return\n\n // INVARIANT 2: prerender skip\n const doc = document as Document & { prerendering?: boolean }\n // visibilityState cast to string to accommodate non-standard 'prerender' value\n if (doc.prerendering === true || (document.visibilityState as string) === 'prerender') return\n\n // INVARIANT 9: skip sends on local hosts in auto mode\n if (sendSuppressed) {\n devSuppressNotice()\n return\n }\n\n // INVARIANT 3: 500ms same-path dedup\n const now = Date.now()\n if (pathname === lastPath && now - lastAt < 500) return\n lastPath = pathname\n lastAt = now\n\n const body = JSON.stringify({\n publishableKey: config.publishableKey,\n pathname,\n referrer: document.referrer || '',\n eventId: newEventId(),\n eventTs: Date.now(),\n })\n\n sendBeaconOrFetch(body)\n }\n\n // -------------------------------------------------------------------------\n // autoTrack: patch history methods + listen to popstate\n // -------------------------------------------------------------------------\n function trackCurrentPath(): void {\n if (destroyed) return\n sendPageview(location.pathname)\n }\n\n function patchedPushState(\n this: History,\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState.apply(this, [data, unused, url] as Parameters<typeof history.pushState>)\n if (!destroyed) setTimeout(trackCurrentPath, 0)\n }\n\n function patchedReplaceState(\n this: History,\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState.apply(this, [data, unused, url] as Parameters<typeof history.replaceState>)\n if (!destroyed) setTimeout(trackCurrentPath, 0)\n }\n\n if (autoTrack) {\n history.pushState = patchedPushState\n history.replaceState = patchedReplaceState\n window.addEventListener('popstate', trackCurrentPath)\n\n // Initial pageview\n if (document.readyState === 'complete') {\n trackCurrentPath()\n } else {\n window.addEventListener('load', trackCurrentPath, { once: true })\n }\n }\n\n // -------------------------------------------------------------------------\n // track() — client-side validation + send\n // -------------------------------------------------------------------------\n\n // Dev-mode detection for warnings: warn in dev, silent in production.\n // Reuses the same local-host signal as the send-skip (INVARIANT 9).\n const isProduction = !isLocalHost\n\n // One-shot warn dedup per reason per page load (keyed by reason only)\n const warnedReasons = new Set<string>()\n\n function devWarn(name: string, reason: string): void {\n if (isProduction) return\n if (warnedReasons.has(reason)) return\n warnedReasons.add(reason)\n console.warn(`[01 analytics] dropped event ${name}: ${reason}`)\n }\n\n const EVENT_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_:-]{0,49}$/\n const RESERVED_PREFIXES = ['__', '_pv_']\n\n function validateEventName(name: string): string | null {\n if (!name || typeof name !== 'string') return 'name-empty'\n for (const prefix of RESERVED_PREFIXES) {\n if (name.startsWith(prefix)) return 'name-reserved'\n }\n if (!EVENT_NAME_RE.test(name)) return 'name-regex'\n return null\n }\n\n const PROP_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,31}$/\n\n function validateEventProps(\n props: Record<string, string | number | boolean> | undefined,\n ): string | null {\n if (props === undefined || props === null) return null\n if (typeof props !== 'object' || Array.isArray(props)) return 'props-value-type'\n const keys = Object.keys(props)\n if (keys.length > 10) return 'props-too-many-keys'\n for (const k of keys) {\n const v = props[k]\n if (!PROP_KEY_RE.test(k)) return 'props-key-regex'\n if (typeof v === 'string') {\n if (v.length > 80) return 'props-value-too-long'\n } else if (typeof v === 'number') {\n if (!isFinite(v)) return 'props-value-not-finite'\n } else if (typeof v === 'boolean') {\n // ok\n } else {\n return 'props-value-type'\n }\n }\n return null\n }\n\n // -------------------------------------------------------------------------\n // Public API\n // -------------------------------------------------------------------------\n return {\n pageview(path?: string): void {\n if (destroyed) return\n sendPageview(path ?? location.pathname)\n },\n\n track(name: string, props?: Record<string, string | number | boolean>): void {\n if (destroyed) return\n\n // INVARIANT 1: DNT/GPC (same as pageview)\n if (isDntActive()) return\n\n // INVARIANT 2: prerender skip\n const doc = document as Document & { prerendering?: boolean }\n if (doc.prerendering === true || (document.visibilityState as string) === 'prerender') return\n\n // Client-side validation\n const nameErr = validateEventName(name)\n if (nameErr) {\n devWarn(name, nameErr)\n return\n }\n\n if (props !== undefined) {\n const propsErr = validateEventProps(props)\n if (propsErr) {\n devWarn(name, propsErr)\n return\n }\n }\n\n // INVARIANT 9: skip sends on local hosts in auto mode (validation above\n // still runs so dev warnings fire)\n if (sendSuppressed) {\n devSuppressNotice()\n return\n }\n\n // Build body — no dedup for track() events\n const body = JSON.stringify({\n publishableKey: config.publishableKey,\n pathname: location.pathname,\n referrer: document.referrer || '',\n eventId: newEventId(),\n eventName: name,\n eventProps: props,\n eventTs: Date.now(),\n })\n\n sendBeaconOrFetch(body)\n },\n\n destroy(): void {\n if (destroyed) return\n destroyed = true\n\n if (autoTrack) {\n // Restore original history methods\n history.pushState = originalPushState\n history.replaceState = originalReplaceState\n window.removeEventListener('popstate', trackCurrentPath)\n }\n\n // Null out dedup state\n lastPath = null\n lastAt = 0\n },\n }\n}\n","export type AnalyticsRuntimeEnv = {\n nextPublicKey?: string\n vitePublicKey?: string\n}\n\nexport function readAnalyticsRuntimeEnv(): AnalyticsRuntimeEnv {\n const nextPublicKey =\n typeof process !== 'undefined'\n ? process.env?.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\n : undefined\n\n const viteEnv = (\n import.meta as ImportMeta & {\n env?: Record<string, string | undefined>\n }\n ).env\n\n return {\n nextPublicKey,\n vitePublicKey: viteEnv?.VITE_SOFTWARE_PUBLISHABLE_KEY,\n }\n}\n\nexport function resolveAnalyticsPublishableKey(\n explicit?: string,\n env: AnalyticsRuntimeEnv = readAnalyticsRuntimeEnv(),\n): string | undefined {\n if (explicit !== undefined) return explicit || undefined\n\n return env.nextPublicKey || env.vitePublicKey\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/analytics/react.tsx","../../src/core/internal/utils/api-url.ts","../../src/analytics.ts","../../src/analytics/env.ts"],"sourcesContent":["'use client'\n\nimport React, {\n createContext,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react'\nimport {\n createAnalytics,\n // Aliased: the local `Analytics` component (value) would otherwise collide\n // with this type during .d.ts bundling, producing unparseable output.\n type Analytics as AnalyticsInstance,\n type AnalyticsConfig,\n type AnalyticsEventMap,\n} from '../analytics'\nimport { resolveAnalyticsPublishableKey } from './env'\n\nexport type AnalyticsProps = Omit<AnalyticsConfig, 'publishableKey'> & {\n publishableKey?: string\n}\n\nexport function Analytics({\n autoTrack,\n endpoint,\n mode,\n publishableKey,\n respectDnt,\n}: AnalyticsProps) {\n useEffect(() => {\n const resolvedPublishableKey =\n resolveAnalyticsPublishableKey(publishableKey)\n if (!resolvedPublishableKey) return\n\n const analytics = createAnalytics({\n autoTrack,\n endpoint,\n mode,\n publishableKey: resolvedPublishableKey,\n respectDnt,\n })\n\n return () => analytics.destroy()\n }, [autoTrack, endpoint, mode, publishableKey, respectDnt])\n\n return null\n}\n\nexport default Analytics\n\n// ============================================================================\n// AnalyticsProvider + useAnalytics\n// ============================================================================\n\ntype AnalyticsContextValue = Pick<AnalyticsInstance, 'track' | 'pageview'> | null\n\nconst AnalyticsContext = createContext<AnalyticsContextValue>(null)\n\nconst NOOP_ANALYTICS: Pick<AnalyticsInstance, 'track' | 'pageview'> = {\n track() {},\n pageview() {},\n} satisfies Pick<AnalyticsInstance, 'track' | 'pageview'>\n\nexport interface AnalyticsProviderProps extends AnalyticsProps {\n children: React.ReactNode\n}\n\nexport function AnalyticsProvider({\n autoTrack,\n endpoint,\n mode,\n publishableKey,\n respectDnt,\n children,\n}: AnalyticsProviderProps): React.ReactElement {\n // Hold one instance for the lifetime of the provider subtree.\n const instanceRef = useRef<AnalyticsInstance | null>(null)\n const [value, setValue] =\n useState<Pick<AnalyticsInstance, 'track' | 'pageview'>>(NOOP_ANALYTICS)\n\n useEffect(() => {\n const resolvedPublishableKey =\n resolveAnalyticsPublishableKey(publishableKey)\n if (!resolvedPublishableKey) return\n\n const analytics = createAnalytics({\n autoTrack,\n endpoint,\n mode,\n publishableKey: resolvedPublishableKey,\n respectDnt,\n })\n instanceRef.current = analytics\n setValue({\n track: (...args: Parameters<AnalyticsInstance['track']>) =>\n instanceRef.current?.track(...args),\n pageview: (path?: string) => instanceRef.current?.pageview(path),\n })\n\n return () => {\n analytics.destroy()\n instanceRef.current = null\n setValue(NOOP_ANALYTICS)\n }\n }, [autoTrack, endpoint, mode, publishableKey, respectDnt])\n\n return (\n <AnalyticsContext.Provider value={value}>\n {children}\n </AnalyticsContext.Provider>\n )\n}\n\nexport function useAnalytics<\n TEvents extends AnalyticsEventMap = AnalyticsEventMap,\n>(): Pick<AnalyticsInstance<TEvents>, 'track' | 'pageview'> {\n const ctx = useContext(AnalyticsContext)\n if (ctx === null) {\n throw new Error(\n 'useAnalytics must be used within an <AnalyticsProvider>.',\n )\n }\n return ctx as Pick<AnalyticsInstance<TEvents>, 'track' | 'pageview'>\n}\n\n/**\n * React counterpart of defineAnalyticsEvents: a typed Provider/hook pair so\n * call sites do not repeat the generic. Runtime values are the shared base\n * Provider/hook; the generic is compile-time only.\n */\nexport function createAnalyticsHooks<TEvents extends AnalyticsEventMap>(): {\n AnalyticsProvider: (props: AnalyticsProviderProps) => React.ReactElement\n useAnalytics: () => Pick<AnalyticsInstance<TEvents>, 'track' | 'pageview'>\n} {\n return {\n AnalyticsProvider,\n useAnalytics: useAnalytics as () => Pick<\n AnalyticsInstance<TEvents>,\n 'track' | 'pageview'\n >,\n }\n}\n","declare const __DEFAULT_API_URL__: string\n\nexport function resolveApiUrl(apiUrl?: string): string {\n if (apiUrl) {\n return apiUrl.replace(/\\/$/, '')\n }\n\n if (typeof process !== 'undefined' && process.env) {\n const envUrl =\n process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL\n if (envUrl) {\n return envUrl.replace(/\\/$/, '')\n }\n }\n return __DEFAULT_API_URL__\n}\n","/**\n * @01.software/sdk — Analytics Helper\n */\n\n/* ANALYTICS INVARIANTS START\n * @01.software/sdk — Analytics Helper\n *\n * ANALYTICS INVARIANTS\n * ====================\n * These invariants are the single source of truth for observable behavior.\n * They are mirrored verbatim in apps/console/src/app/api/analytics/script.js/route.ts.\n * Any change here MUST be reflected there, and vice versa.\n *\n * 1. DNT/GPC respect: when config.respectDnt !== false (default true) AND\n * (navigator.doNotTrack === '1' OR navigator.globalPrivacyControl === true),\n * all methods become no-ops. Zero network requests are made.\n *\n * 2. Prerender skip: when document.prerendering === true OR\n * document.visibilityState === 'prerender', pageview() sends zero requests.\n *\n * 3. 500ms same-path dedup: a pageview for the same pathname within 500ms of\n * the previous send is silently dropped. After 500ms the next call sends.\n *\n * 4. Transport: sendBeacon → fetch keepalive fallback.\n * Primary: navigator.sendBeacon(endpoint, new Blob([json], { type: 'text/plain' })).\n * Fallback (sendBeacon unavailable OR returns false):\n * fetch(endpoint, { method: 'POST', keepalive: true,\n * headers: { 'Content-Type': 'application/json' }, body: json }).catch(() => {})\n *\n * 5. Body-only publishableKey: publishableKey is always in the request body,\n * never in any HTTP header.\n *\n * 6. SSR no-op: when typeof window === 'undefined', createAnalytics() returns\n * a stub where all methods are no-ops. No side effects occur.\n *\n * 7. Error swallowing: all transport errors are caught and swallowed.\n * createAnalytics() and all returned methods never throw into the caller.\n *\n * 8. Client timestamp: every send carries eventTs (milliseconds since epoch)\n * captured with Date.now() immediately before transport. The collect\n * endpoint uses eventTs (a) to bucket the event into the client's\n * tenant-local day and (b) to enforce the late-arrival cutoff; events\n * submitted after the local-day-end grace window are dropped with\n * reason \"late\".\n *\n * 9. Dev / local-host send skip: in 'auto' mode (the default) all send paths\n * become no-ops when the page runs on a local host — location.hostname is\n * 'localhost', '127.0.0.1', or ends with '.local'. Validation and dev\n * warnings still run; only the network send is suppressed, and a one-time\n * console notice is emitted. SSR (6), DNT/GPC (1), and prerender (2) skips\n * are evaluated first. Overrides: both the SDK and the mirrored hosted\n * snippet accept mode 'production' (always send, even locally) and\n * 'development' (never send, on any host); 'auto' is the default. The\n * snippet reads mode from window.__01_analytics__.mode or the script's\n * data-mode attribute. For backward compatibility the snippet also accepts\n * captureOnLocalhost === true (via window.__01_analytics__.captureOnLocalhost\n * or data-capture-localhost), equivalent to mode 'production' when mode is\n * unset; an explicit mode wins.\n * ANALYTICS INVARIANTS END */\n\nimport { resolveApiUrl } from './core/internal/utils/api-url'\n\n// ============================================================================\n// Public Types\n// ============================================================================\n\nexport interface AnalyticsConfig {\n publishableKey: string\n /** Override the collect endpoint URL. Defaults to {SDK_BASE_URL}/api/analytics/collect */\n endpoint?: string\n /** Auto-patch history.pushState/replaceState and listen to popstate. Default: true */\n autoTrack?: boolean\n /** Respect navigator.doNotTrack and navigator.globalPrivacyControl. Default: true */\n respectDnt?: boolean\n /**\n * Send mode. 'auto' (default) skips all sends on local hosts\n * (localhost / 127.0.0.1 / *.local). 'production' always sends, even\n * locally. 'development' never sends, on any host. See INVARIANT 9.\n */\n mode?: 'auto' | 'production' | 'development'\n}\n\nexport type AnalyticsEventProps = Record<string, string | number | boolean>\n\nexport type AnalyticsEventMap = Record<string, AnalyticsEventProps | undefined>\n\n/**\n * Argument tuple for `track`. The default open map keeps `props` optional\n * (back-compat). A developer-declared closed map makes `props` required when\n * the event declares props, and omittable when the event value is `undefined`.\n */\nexport type TrackArgs<\n TEvents extends AnalyticsEventMap,\n K extends keyof TEvents & string,\n> = string extends keyof TEvents\n ? [props?: AnalyticsEventProps]\n : undefined extends TEvents[K]\n ? [props?: Exclude<TEvents[K], undefined>]\n : [props: TEvents[K]]\n\nexport interface Analytics<\n TEvents extends AnalyticsEventMap = AnalyticsEventMap,\n> {\n pageview(path?: string): void\n track<K extends keyof TEvents & string>(\n name: K,\n ...args: TrackArgs<TEvents, K>\n ): void\n destroy(): void\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\nexport function createAnalytics<\n TEvents extends AnalyticsEventMap = AnalyticsEventMap,\n>(config: AnalyticsConfig): Analytics<TEvents> {\n // INVARIANT 6: SSR no-op\n if (typeof window === 'undefined') {\n return { pageview() {}, track() {}, destroy() {} } as Analytics<TEvents>\n }\n\n const endpoint =\n config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`\n\n // INVARIANT 1: DNT/GPC check (evaluated once at init; stays as closure)\n const respectDnt = config.respectDnt !== false\n function isDntActive(): boolean {\n if (!respectDnt) return false\n const nav = navigator as Navigator & { globalPrivacyControl?: boolean }\n return nav.doNotTrack === '1' || nav.globalPrivacyControl === true\n }\n\n // INVARIANT 9: local-host detection drives both dev warnings and the\n // auto send-skip. Hostname is the one signal shared with the hosted snippet.\n const isLocalHost: boolean = (() => {\n try {\n const h = location.hostname\n return h === 'localhost' || h === '127.0.0.1' || h.endsWith('.local')\n } catch {\n return false\n }\n })()\n\n const mode = config.mode ?? 'auto'\n const sendSuppressed =\n mode === 'development' || (mode === 'auto' && isLocalHost)\n\n let suppressNoticeShown = false\n function devSuppressNotice(): void {\n if (suppressNoticeShown) return\n suppressNoticeShown = true\n try {\n console.info(\n `[01 analytics] events disabled on local host (mode: '${mode}'). ` +\n `Pass mode: 'production' to send while developing.`,\n )\n } catch {\n // INVARIANT 7: swallow\n }\n }\n\n // INVARIANT 3: 500ms same-path dedup state\n let lastPath: string | null = null\n let lastAt = 0\n\n // autoTrack state — save originals for destroy()\n const autoTrack = config.autoTrack !== false\n const originalPushState = history.pushState\n const originalReplaceState = history.replaceState\n let destroyed = false\n\n // -------------------------------------------------------------------------\n // Core send logic\n // -------------------------------------------------------------------------\n\n // Generate a unique event ID (crypto.randomUUID when available, Date+Math.random fallback)\n function newEventId(): string {\n return typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID()\n : String(Date.now()) + String(Math.random())\n }\n\n // INVARIANT 4: sendBeacon → fetch keepalive fallback\n // INVARIANT 5: publishableKey in body only\n function sendBeaconOrFetch(body: string): void {\n try {\n if (typeof navigator.sendBeacon === 'function') {\n const blob = new Blob([body], { type: 'text/plain' })\n const sent = navigator.sendBeacon(endpoint, blob)\n if (sent) return\n // sent === false → fall through to fetch\n }\n // Fetch fallback\n fetch(endpoint, {\n method: 'POST',\n keepalive: true,\n headers: { 'Content-Type': 'application/json' },\n body,\n }).catch(() => {})\n } catch {\n // INVARIANT 7: swallow all errors\n }\n }\n\n function sendPageview(pathname: string): void {\n // INVARIANT 1: DNT/GPC\n if (isDntActive()) return\n\n // INVARIANT 2: prerender skip\n const doc = document as Document & { prerendering?: boolean }\n // visibilityState cast to string to accommodate non-standard 'prerender' value\n if (doc.prerendering === true || (document.visibilityState as string) === 'prerender') return\n\n // INVARIANT 9: skip sends on local hosts in auto mode\n if (sendSuppressed) {\n devSuppressNotice()\n return\n }\n\n // INVARIANT 3: 500ms same-path dedup\n const now = Date.now()\n if (pathname === lastPath && now - lastAt < 500) return\n lastPath = pathname\n lastAt = now\n\n const body = JSON.stringify({\n publishableKey: config.publishableKey,\n pathname,\n referrer: document.referrer || '',\n eventId: newEventId(),\n eventTs: Date.now(),\n })\n\n sendBeaconOrFetch(body)\n }\n\n // -------------------------------------------------------------------------\n // autoTrack: patch history methods + listen to popstate\n // -------------------------------------------------------------------------\n function trackCurrentPath(): void {\n if (destroyed) return\n sendPageview(location.pathname)\n }\n\n function patchedPushState(\n this: History,\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState.apply(this, [data, unused, url] as Parameters<typeof history.pushState>)\n if (!destroyed) setTimeout(trackCurrentPath, 0)\n }\n\n function patchedReplaceState(\n this: History,\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState.apply(this, [data, unused, url] as Parameters<typeof history.replaceState>)\n if (!destroyed) setTimeout(trackCurrentPath, 0)\n }\n\n if (autoTrack) {\n history.pushState = patchedPushState\n history.replaceState = patchedReplaceState\n window.addEventListener('popstate', trackCurrentPath)\n\n // Initial pageview\n if (document.readyState === 'complete') {\n trackCurrentPath()\n } else {\n window.addEventListener('load', trackCurrentPath, { once: true })\n }\n }\n\n // -------------------------------------------------------------------------\n // track() — client-side validation + send\n // -------------------------------------------------------------------------\n\n // Dev-mode detection for warnings: warn in dev, silent in production.\n // Reuses the same local-host signal as the send-skip (INVARIANT 9).\n const isProduction = !isLocalHost\n\n // One-shot warn dedup per reason per page load (keyed by reason only)\n const warnedReasons = new Set<string>()\n\n function devWarn(name: string, reason: string): void {\n if (isProduction) return\n if (warnedReasons.has(reason)) return\n warnedReasons.add(reason)\n console.warn(`[01 analytics] dropped event ${name}: ${reason}`)\n }\n\n const EVENT_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_:-]{0,49}$/\n const RESERVED_PREFIXES = ['__', '_pv_']\n\n function validateEventName(name: string): string | null {\n if (!name || typeof name !== 'string') return 'name-empty'\n for (const prefix of RESERVED_PREFIXES) {\n if (name.startsWith(prefix)) return 'name-reserved'\n }\n if (!EVENT_NAME_RE.test(name)) return 'name-regex'\n return null\n }\n\n const PROP_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]{0,31}$/\n\n function validateEventProps(\n props: Record<string, string | number | boolean> | undefined,\n ): string | null {\n if (props === undefined || props === null) return null\n if (typeof props !== 'object' || Array.isArray(props)) return 'props-value-type'\n const keys = Object.keys(props)\n if (keys.length > 10) return 'props-too-many-keys'\n for (const k of keys) {\n const v = props[k]\n if (!PROP_KEY_RE.test(k)) return 'props-key-regex'\n if (typeof v === 'string') {\n if (v.length > 80) return 'props-value-too-long'\n } else if (typeof v === 'number') {\n if (!isFinite(v)) return 'props-value-not-finite'\n } else if (typeof v === 'boolean') {\n // ok\n } else {\n return 'props-value-type'\n }\n }\n return null\n }\n\n // -------------------------------------------------------------------------\n // Public API\n // -------------------------------------------------------------------------\n return {\n pageview(path?: string): void {\n if (destroyed) return\n sendPageview(path ?? location.pathname)\n },\n\n track(name: string, props?: Record<string, string | number | boolean>): void {\n if (destroyed) return\n\n // INVARIANT 1: DNT/GPC (same as pageview)\n if (isDntActive()) return\n\n // INVARIANT 2: prerender skip\n const doc = document as Document & { prerendering?: boolean }\n if (doc.prerendering === true || (document.visibilityState as string) === 'prerender') return\n\n // Client-side validation\n const nameErr = validateEventName(name)\n if (nameErr) {\n devWarn(name, nameErr)\n return\n }\n\n if (props !== undefined) {\n const propsErr = validateEventProps(props)\n if (propsErr) {\n devWarn(name, propsErr)\n return\n }\n }\n\n // INVARIANT 9: skip sends on local hosts in auto mode (validation above\n // still runs so dev warnings fire)\n if (sendSuppressed) {\n devSuppressNotice()\n return\n }\n\n // Build body — no dedup for track() events\n const body = JSON.stringify({\n publishableKey: config.publishableKey,\n pathname: location.pathname,\n referrer: document.referrer || '',\n eventId: newEventId(),\n eventName: name,\n eventProps: props,\n eventTs: Date.now(),\n })\n\n sendBeaconOrFetch(body)\n },\n\n destroy(): void {\n if (destroyed) return\n destroyed = true\n\n if (autoTrack) {\n // Restore original history methods\n history.pushState = originalPushState\n history.replaceState = originalReplaceState\n window.removeEventListener('popstate', trackCurrentPath)\n }\n\n // Null out dedup state\n lastPath = null\n lastAt = 0\n },\n } as Analytics<TEvents>\n}\n\n/**\n * Bind a typed event map once, then create instances without repeating the\n * generic. Equivalent to `createAnalytics<TEvents>(config)`.\n */\nexport function defineAnalyticsEvents<\n TEvents extends AnalyticsEventMap,\n>(): (config: AnalyticsConfig) => Analytics<TEvents> {\n return (config) => createAnalytics<TEvents>(config)\n}\n","export type AnalyticsRuntimeEnv = {\n nextPublicKey?: string\n vitePublicKey?: string\n}\n\nexport function readAnalyticsRuntimeEnv(): AnalyticsRuntimeEnv {\n const nextPublicKey =\n typeof process !== 'undefined'\n ? process.env?.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\n : undefined\n\n const viteEnv = (\n import.meta as ImportMeta & {\n env?: Record<string, string | undefined>\n }\n ).env\n\n return {\n nextPublicKey,\n vitePublicKey: viteEnv?.VITE_SOFTWARE_PUBLISHABLE_KEY,\n }\n}\n\nexport function resolveAnalyticsPublishableKey(\n explicit?: string,\n env: AnalyticsRuntimeEnv = readAnalyticsRuntimeEnv(),\n): string | undefined {\n if (explicit !== undefined) return explicit || undefined\n\n return env.nextPublicKey || env.vitePublicKey\n}\n"],"mappings":"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","names":["React"]}
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AnalyticsConfig, AnalyticsEventMap, Analytics as Analytics$1 } from '../analytics.cjs';
|
|
2
3
|
|
|
3
4
|
type AnalyticsProps = Omit<AnalyticsConfig, 'publishableKey'> & {
|
|
4
5
|
publishableKey?: string;
|
|
5
6
|
};
|
|
6
7
|
declare function Analytics({ autoTrack, endpoint, mode, publishableKey, respectDnt, }: AnalyticsProps): null;
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
interface AnalyticsProviderProps extends AnalyticsProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare function AnalyticsProvider({ autoTrack, endpoint, mode, publishableKey, respectDnt, children, }: AnalyticsProviderProps): React.ReactElement;
|
|
13
|
+
declare function useAnalytics<TEvents extends AnalyticsEventMap = AnalyticsEventMap>(): Pick<Analytics$1<TEvents>, 'track' | 'pageview'>;
|
|
14
|
+
/**
|
|
15
|
+
* React counterpart of defineAnalyticsEvents: a typed Provider/hook pair so
|
|
16
|
+
* call sites do not repeat the generic. Runtime values are the shared base
|
|
17
|
+
* Provider/hook; the generic is compile-time only.
|
|
18
|
+
*/
|
|
19
|
+
declare function createAnalyticsHooks<TEvents extends AnalyticsEventMap>(): {
|
|
20
|
+
AnalyticsProvider: (props: AnalyticsProviderProps) => React.ReactElement;
|
|
21
|
+
useAnalytics: () => Pick<Analytics$1<TEvents>, 'track' | 'pageview'>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { Analytics, type AnalyticsProps, AnalyticsProvider, type AnalyticsProviderProps, createAnalyticsHooks, Analytics as default, useAnalytics };
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AnalyticsConfig, AnalyticsEventMap, Analytics as Analytics$1 } from '../analytics.js';
|
|
2
3
|
|
|
3
4
|
type AnalyticsProps = Omit<AnalyticsConfig, 'publishableKey'> & {
|
|
4
5
|
publishableKey?: string;
|
|
5
6
|
};
|
|
6
7
|
declare function Analytics({ autoTrack, endpoint, mode, publishableKey, respectDnt, }: AnalyticsProps): null;
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
interface AnalyticsProviderProps extends AnalyticsProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare function AnalyticsProvider({ autoTrack, endpoint, mode, publishableKey, respectDnt, children, }: AnalyticsProviderProps): React.ReactElement;
|
|
13
|
+
declare function useAnalytics<TEvents extends AnalyticsEventMap = AnalyticsEventMap>(): Pick<Analytics$1<TEvents>, 'track' | 'pageview'>;
|
|
14
|
+
/**
|
|
15
|
+
* React counterpart of defineAnalyticsEvents: a typed Provider/hook pair so
|
|
16
|
+
* call sites do not repeat the generic. Runtime values are the shared base
|
|
17
|
+
* Provider/hook; the generic is compile-time only.
|
|
18
|
+
*/
|
|
19
|
+
declare function createAnalyticsHooks<TEvents extends AnalyticsEventMap>(): {
|
|
20
|
+
AnalyticsProvider: (props: AnalyticsProviderProps) => React.ReactElement;
|
|
21
|
+
useAnalytics: () => Pick<Analytics$1<TEvents>, 'track' | 'pageview'>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { Analytics, type AnalyticsProps, AnalyticsProvider, type AnalyticsProviderProps, createAnalyticsHooks, Analytics as default, useAnalytics };
|