@ductape/mcp 0.1.49 → 0.1.50
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/dist/index.js +255 -9
- package/package.json +2 -1
- package/scripts/check-frontend-analytics-guidance.mjs +37 -0
- package/src/index.ts +256 -9
package/dist/index.js
CHANGED
|
@@ -1192,7 +1192,7 @@ const docsInputSchema = z.object({
|
|
|
1192
1192
|
topic: z.string().describe('Feature topic to look up. Supported: ' +
|
|
1193
1193
|
'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
|
|
1194
1194
|
'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
|
|
1195
|
-
'notifications, resilience, features, events, logs, frontend, client, react, vue'),
|
|
1195
|
+
'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue'),
|
|
1196
1196
|
});
|
|
1197
1197
|
const DOCS = {
|
|
1198
1198
|
frontend: `
|
|
@@ -1228,6 +1228,11 @@ SHARED APPLICATION LIFECYCLE
|
|
|
1228
1228
|
connectionState to render disconnected/reconnecting UI; do not create duplicate subscriptions.
|
|
1229
1229
|
7. Disconnect resource sessions and the root client when the owning application scope is torn down.
|
|
1230
1230
|
|
|
1231
|
+
PRODUCT ANALYTICS
|
|
1232
|
+
Frontend product analytics complements backend session propagation; neither replaces the other.
|
|
1233
|
+
Continue with ductape_docs({ topic: "frontend-analytics" }) for identity lifecycle, pageviews,
|
|
1234
|
+
custom events, privacy masking, hidden-state safety, trace correlation, and package-version checks.
|
|
1235
|
+
|
|
1231
1236
|
AUTHENTICATION AND SECURITY
|
|
1232
1237
|
- Use publishableKey in browser applications. Never ship workspace private keys or privileged
|
|
1233
1238
|
access keys in frontend bundles.
|
|
@@ -1973,6 +1978,7 @@ Resource registration (all via ductape_cli or ductape_execute — see per-topic
|
|
|
1973
1978
|
caches → ductape_docs({ topic: "caches" })
|
|
1974
1979
|
notifications → ductape_docs({ topic: "notifications" })
|
|
1975
1980
|
sessions → ductape_docs({ topic: "sessions" })
|
|
1981
|
+
frontend analytics → ductape_docs({ topic: "frontend-analytics" })
|
|
1976
1982
|
resilience → ductape_docs({ topic: "resilience" })
|
|
1977
1983
|
features → ductape_docs({ topic: "features" })
|
|
1978
1984
|
|
|
@@ -2060,6 +2066,16 @@ Analytics:
|
|
|
2060
2066
|
|
|
2061
2067
|
Token format: "session_tag:jwt_token" — pass this format verbatim wherever session is expected.
|
|
2062
2068
|
JWT is signed with the product private key (not a symmetric shared secret).
|
|
2069
|
+
|
|
2070
|
+
SESSION PROPAGATION
|
|
2071
|
+
Preserve the original full token on every user-context database, Event, Feature, notification,
|
|
2072
|
+
storage, graph, vector, action, and other runtime operation that accepts session. Do not replace
|
|
2073
|
+
it with the session tag, user ID, decoded claims, or refresh token. Durable user-initiated work
|
|
2074
|
+
should retain the initiating token; intentional system/background work should be sessionless.
|
|
2075
|
+
|
|
2076
|
+
Backend propagation attributes component activity to an actor, but it does not record frontend
|
|
2077
|
+
pageviews, navigation, UI intent, funnels, or client failures. Continue immediately with
|
|
2078
|
+
ductape_docs({ topic: "frontend-analytics" }); both layers are required for a complete picture.
|
|
2063
2079
|
`.trim(),
|
|
2064
2080
|
caches: `
|
|
2065
2081
|
DUCTAPE CACHES
|
|
@@ -2222,6 +2238,222 @@ Failure actions: notification channels, HTTP webhooks, and/or message broker emi
|
|
|
2222
2238
|
be configured simultaneously on the same healthcheck.
|
|
2223
2239
|
Input template references: $Input{field} → maps declared input to the probe's action input.
|
|
2224
2240
|
Provider status: available | unavailable
|
|
2241
|
+
`.trim(),
|
|
2242
|
+
'frontend-analytics': `
|
|
2243
|
+
DUCTAPE FRONTEND PRODUCT ANALYTICS AND SESSION ACTIVITY
|
|
2244
|
+
|
|
2245
|
+
Frontend analytics and backend session attribution are complementary; neither replaces the other.
|
|
2246
|
+
|
|
2247
|
+
BACKEND OPERATION ATTRIBUTION
|
|
2248
|
+
Pass the original full Ductape session token to every user-initiated database, Event, Feature,
|
|
2249
|
+
notification, storage, graph, vector, action, and other runtime operation that accepts session.
|
|
2250
|
+
This attributes server work to the authenticated actor. Durable work should retain the initiating
|
|
2251
|
+
session; intentional system/background work should remain sessionless.
|
|
2252
|
+
|
|
2253
|
+
FRONTEND PRODUCT ANALYTICS
|
|
2254
|
+
Use the browser Analytics service for anonymous visits, authenticated page views, navigation,
|
|
2255
|
+
UI interactions, funnels, client errors, realtime state, and product-surface engagement.
|
|
2256
|
+
|
|
2257
|
+
IMPORTANT:
|
|
2258
|
+
Passing session to backend component calls does not replace frontend analytics.
|
|
2259
|
+
Calling analytics.identify(sessionToken) and tracking frontend events does not replace backend
|
|
2260
|
+
session propagation. A complete activity picture requires both.
|
|
2261
|
+
|
|
2262
|
+
VERSION AND DOCUMENTATION PRECEDENCE
|
|
2263
|
+
1. Installed package types and exports determine what can be called now.
|
|
2264
|
+
2. Version-matched package documentation explains intended usage.
|
|
2265
|
+
3. Current docs/docs/Frontend describes the latest supported design.
|
|
2266
|
+
4. If they disagree, report the mismatch; never fabricate compatibility.
|
|
2267
|
+
|
|
2268
|
+
Inspect package.json plus package exports/type declarations before recommending framework hooks.
|
|
2269
|
+
The current repository exports useAnalytics from @ductape/react and @ductape/vue. Their installed
|
|
2270
|
+
hook/composable exposes track, pageview, identify, visitorId, enableAutoCapture, and flush.
|
|
2271
|
+
clearSession and disableAutoCapture are available on client.analytics but are not currently
|
|
2272
|
+
returned by those framework wrappers. Use useDuctape().client.analytics for those calls, or
|
|
2273
|
+
recommend a package version that exports them; do not generate a hook method that does not exist.
|
|
2274
|
+
|
|
2275
|
+
CLIENT API — IDENTIFY AFTER AUTHENTICATION
|
|
2276
|
+
ductape.analytics.identify(sessionToken);
|
|
2277
|
+
|
|
2278
|
+
sessionToken is the complete value returned by Ductape, in "player-session:jwt" format.
|
|
2279
|
+
It is NOT a player ID, session tag, session ID, decoded claims, or refresh token.
|
|
2280
|
+
identify links subsequent frontend analytics to the authenticated Ductape session and lets
|
|
2281
|
+
supported analytics correlate anonymous pre-login activity with authenticated activity.
|
|
2282
|
+
|
|
2283
|
+
LOGOUT / ACCOUNT SWITCHING
|
|
2284
|
+
await ductape.analytics.flush();
|
|
2285
|
+
ductape.analytics.clearSession();
|
|
2286
|
+
|
|
2287
|
+
Clear analytics identity when logout or revocation succeeds, refresh fails irrecoverably, local
|
|
2288
|
+
authentication is removed, or a different user is about to authenticate in the same browser.
|
|
2289
|
+
Removing only the application token can leave later anonymous/next-user events associated with
|
|
2290
|
+
the previous analytics identity. Flush is best-effort; browser shutdown does not guarantee it.
|
|
2291
|
+
|
|
2292
|
+
CUSTOM EVENTS
|
|
2293
|
+
await ductape.analytics.track({
|
|
2294
|
+
event: 'order_submitted',
|
|
2295
|
+
traceId,
|
|
2296
|
+
properties: { matchId, orderType },
|
|
2297
|
+
});
|
|
2298
|
+
|
|
2299
|
+
IAnalyticsTrackOptions:
|
|
2300
|
+
event: string
|
|
2301
|
+
properties?: Record<string, unknown>
|
|
2302
|
+
session?: string
|
|
2303
|
+
product?: string
|
|
2304
|
+
env?: string
|
|
2305
|
+
traceId?: string
|
|
2306
|
+
context?: { url?, path?, referrer?, locale?, screen?: { width, height } }
|
|
2307
|
+
|
|
2308
|
+
identify establishes the default analytics session. An individual event may explicitly provide
|
|
2309
|
+
session. Normally use product/env from client configuration. traceId correlates frontend intent
|
|
2310
|
+
with backend logs, Events, Features, and order processing.
|
|
2311
|
+
|
|
2312
|
+
PAGE VIEWS
|
|
2313
|
+
await ductape.analytics.pageview({
|
|
2314
|
+
path: location.pathname,
|
|
2315
|
+
title: document.title,
|
|
2316
|
+
properties: { matchId, screen: 'governance' },
|
|
2317
|
+
});
|
|
2318
|
+
|
|
2319
|
+
IAnalyticsPageviewOptions:
|
|
2320
|
+
path?: string
|
|
2321
|
+
title?: string
|
|
2322
|
+
session?: string
|
|
2323
|
+
product?: string
|
|
2324
|
+
env?: string
|
|
2325
|
+
properties?: Record<string, unknown>
|
|
2326
|
+
|
|
2327
|
+
AUTO-CAPTURE — OPT IN ONLY AFTER A PRIVACY AUDIT
|
|
2328
|
+
const stopAutoCapture = ductape.analytics.enableAutoCapture({
|
|
2329
|
+
session: () => authSession?.token,
|
|
2330
|
+
clicks: false,
|
|
2331
|
+
pageviews: true,
|
|
2332
|
+
maskTextSelectors: [
|
|
2333
|
+
'[data-private]',
|
|
2334
|
+
'[data-secret]',
|
|
2335
|
+
'[data-player-message]',
|
|
2336
|
+
'[data-intelligence-report]',
|
|
2337
|
+
],
|
|
2338
|
+
});
|
|
2339
|
+
stopAutoCapture(); // or ductape.analytics.disableAutoCapture()
|
|
2340
|
+
|
|
2341
|
+
Mark sensitive UI with data-private/data-secret attributes. Text masking may not mask attributes,
|
|
2342
|
+
IDs, URLs, element names, custom properties, console errors, or network errors. Inspect actual
|
|
2343
|
+
payloads before production. For hidden-information products, begin with reviewed automatic
|
|
2344
|
+
pageviews, clicks disabled, and preferred custom named events.
|
|
2345
|
+
|
|
2346
|
+
VISITOR ID
|
|
2347
|
+
const visitorId = ductape.analytics.getVisitorId();
|
|
2348
|
+
A visitor ID is anonymous analytics identity, not authentication or authorization.
|
|
2349
|
+
|
|
2350
|
+
FRONTEND SESSION LIFECYCLE
|
|
2351
|
+
Before login:
|
|
2352
|
+
- Track anonymous pageviews/onboarding; do not invent a session.
|
|
2353
|
+
After login/registration:
|
|
2354
|
+
- Store the session securely, identify(fullSessionToken), track success, start authenticated
|
|
2355
|
+
pageviews, and pass the same token to user-context realtime/component operations.
|
|
2356
|
+
After refresh:
|
|
2357
|
+
- Replace the old token, identify(newSessionToken), update realtime connections/subscriptions,
|
|
2358
|
+
and use the refreshed token for future backend operations.
|
|
2359
|
+
Logout:
|
|
2360
|
+
- Optionally track logout_initiated, flush, revoke, disconnect realtime, clearSession, then
|
|
2361
|
+
remove local authentication.
|
|
2362
|
+
Refresh failure/revocation:
|
|
2363
|
+
- Disconnect user-context clients, clearSession, clear local auth, navigate to authentication,
|
|
2364
|
+
and track only anonymous events afterward.
|
|
2365
|
+
|
|
2366
|
+
REACT ROUTE TRACKING (verify installed exports first)
|
|
2367
|
+
import { useAnalytics, useDuctape } from '@ductape/react';
|
|
2368
|
+
import { useEffect } from 'react';
|
|
2369
|
+
import { useLocation } from 'react-router-dom';
|
|
2370
|
+
|
|
2371
|
+
function ProductAnalytics({ sessionToken }: { sessionToken?: string }) {
|
|
2372
|
+
const analytics = useAnalytics();
|
|
2373
|
+
const { client } = useDuctape();
|
|
2374
|
+
const location = useLocation();
|
|
2375
|
+
useEffect(() => {
|
|
2376
|
+
if (sessionToken) analytics.identify(sessionToken);
|
|
2377
|
+
else client.analytics.clearSession();
|
|
2378
|
+
}, [analytics, client, sessionToken]);
|
|
2379
|
+
useEffect(() => {
|
|
2380
|
+
void analytics.pageview({ path: location.pathname, title: document.title });
|
|
2381
|
+
}, [analytics, location.pathname]);
|
|
2382
|
+
return null;
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
SAFE EVENT TAXONOMY
|
|
2386
|
+
Define stable names centrally; do not invent variants throughout components.
|
|
2387
|
+
Authentication:
|
|
2388
|
+
registration_started, registration_completed, registration_failed,
|
|
2389
|
+
login_started, login_completed, login_failed, session_refreshed,
|
|
2390
|
+
session_refresh_failed, logout_completed
|
|
2391
|
+
Match:
|
|
2392
|
+
match_list_viewed, match_creation_started, match_created, match_joined, lobby_viewed,
|
|
2393
|
+
player_marked_ready, match_preparation_started, world_loaded, match_reconnected,
|
|
2394
|
+
match_completed, endgame_viewed
|
|
2395
|
+
Orders:
|
|
2396
|
+
order_form_opened, order_previewed, order_submission_started, order_submitted,
|
|
2397
|
+
order_submission_failed, order_cancelled, boundary_result_viewed
|
|
2398
|
+
Realtime:
|
|
2399
|
+
realtime_connect_started, realtime_connected, realtime_disconnected,
|
|
2400
|
+
realtime_reconnect_attempted, realtime_subscription_failed, projection_refresh_failed,
|
|
2401
|
+
client_error
|
|
2402
|
+
Funnels:
|
|
2403
|
+
tutorial_started, tutorial_step_completed, tutorial_abandoned, first_match_created,
|
|
2404
|
+
first_order_submitted, first_boundary_viewed, first_match_completed
|
|
2405
|
+
|
|
2406
|
+
Safe properties include matchId, orderType, screen, tick, result, and errorCategory.
|
|
2407
|
+
|
|
2408
|
+
HIDDEN AND SENSITIVE DATA — NEVER SEND TO ANALYTICS
|
|
2409
|
+
Do not track exact hidden formations, operative/handler identities, secret operation payloads,
|
|
2410
|
+
false-report truth markers, undiscovered evasion details, invisible treaties, canonical hidden
|
|
2411
|
+
map state, private messages, passwords, authorization headers, session/refresh tokens in event
|
|
2412
|
+
properties, or full errors/records that may contain secrets. Analytics must observe usage, not
|
|
2413
|
+
become a hidden-state side channel.
|
|
2414
|
+
|
|
2415
|
+
CORRELATION
|
|
2416
|
+
Frontend: create traceId = crypto.randomUUID(), track intent with traceId, and send traceId with
|
|
2417
|
+
the actual request. Backend logs the same traceId and propagates session to Ductape operations.
|
|
2418
|
+
Track completion with the same traceId.
|
|
2419
|
+
|
|
2420
|
+
traceId = correlation
|
|
2421
|
+
session = actor attribution
|
|
2422
|
+
idempotencyKey = duplicate prevention
|
|
2423
|
+
matchId/orderId = domain identity
|
|
2424
|
+
These values are not interchangeable.
|
|
2425
|
+
|
|
2426
|
+
OWNERSHIP BOUNDARIES
|
|
2427
|
+
Analytics is never an authoritative order, authorization proof, or gameplay source of truth.
|
|
2428
|
+
Analytics failure must not block or alter gameplay. The server verifies sessions independently;
|
|
2429
|
+
authoritative database and Event streams remain the source of truth. Prefer non-blocking
|
|
2430
|
+
analytics except explicit best-effort flushes at safe lifecycle transitions.
|
|
2431
|
+
|
|
2432
|
+
FRONTEND PROJECT AUDIT
|
|
2433
|
+
Inspect installed @ductape/client/react/vue versions and actual exports; client/provider setup;
|
|
2434
|
+
identify after login and refresh; clearSession on logout/account switch; SPA pageviews; auto-
|
|
2435
|
+
capture and masking; taxonomy consistency; sensitive custom properties; and shared trace IDs.
|
|
2436
|
+
Report capability as Present/Missing/Partial/Not applicable with concrete findings.
|
|
2437
|
+
|
|
2438
|
+
WHEN “SESSION ACTIVITY IS MISSING FROM THE DASHBOARD”
|
|
2439
|
+
Investigate both tracks before blaming the SDK.
|
|
2440
|
+
Backend: start/verify format, correct env, session on database/Event/Feature/notification/etc.,
|
|
2441
|
+
and intentional background sessionlessness.
|
|
2442
|
+
Frontend: identify after login/refresh, clearSession on logout, pageviews/custom events, flush,
|
|
2443
|
+
correct publishable key/product/env, installed API compatibility, browser failures, and privacy
|
|
2444
|
+
controls that may suppress events.
|
|
2445
|
+
|
|
2446
|
+
PAYLOAD RECIPES
|
|
2447
|
+
Anonymous:
|
|
2448
|
+
await ductape.analytics.pageview({ path: window.location.pathname, title: document.title });
|
|
2449
|
+
Authenticated:
|
|
2450
|
+
ductape.analytics.identify(playerSessionToken);
|
|
2451
|
+
await ductape.analytics.track({
|
|
2452
|
+
event: 'match_created', session: playerSessionToken, traceId, properties: { matchId },
|
|
2453
|
+
});
|
|
2454
|
+
Logout:
|
|
2455
|
+
await ductape.analytics.flush();
|
|
2456
|
+
ductape.analytics.clearSession();
|
|
2225
2457
|
`.trim(),
|
|
2226
2458
|
features: `
|
|
2227
2459
|
DUCTAPE FEATURES
|
|
@@ -2907,9 +3139,15 @@ SESSIONS SERVICE
|
|
|
2907
3139
|
const { token } = await ductape.sessions.refresh({ refreshToken: '...' });
|
|
2908
3140
|
|
|
2909
3141
|
ANALYTICS SERVICE
|
|
2910
|
-
ductape.analytics.
|
|
2911
|
-
ductape.analytics.
|
|
2912
|
-
ductape.analytics.
|
|
3142
|
+
ductape.analytics.identify('player-session:eyJ...'); // full Ductape session token
|
|
3143
|
+
await ductape.analytics.pageview({ path: '/dashboard', title: document.title });
|
|
3144
|
+
await ductape.analytics.track({
|
|
3145
|
+
event: 'button_clicked',
|
|
3146
|
+
properties: { button: 'sign-up' },
|
|
3147
|
+
});
|
|
3148
|
+
await ductape.analytics.flush();
|
|
3149
|
+
ductape.analytics.clearSession(); // logout/account switch
|
|
3150
|
+
See ductape_docs({ topic: "frontend-analytics" }) before enabling auto-capture.
|
|
2913
3151
|
|
|
2914
3152
|
FRAMEWORK-SPECIFIC PACKAGES
|
|
2915
3153
|
For React and Vue projects, use the dedicated packages instead of managing the client manually:
|
|
@@ -3010,13 +3248,15 @@ AGENT HOOKS
|
|
|
3010
3248
|
useAgentSignal(hookOptions?) → { mutate, isLoading, error }
|
|
3011
3249
|
|
|
3012
3250
|
BROKER HOOKS
|
|
3013
|
-
useBroker(
|
|
3251
|
+
useBroker()
|
|
3014
3252
|
→ { isConnected, isConnecting, error, connect, disconnect }
|
|
3253
|
+
connect({ broker, session?, product?, env? }) forwards the complete options object to
|
|
3254
|
+
@ductape/client. Pass session for player-scoped authorization.
|
|
3015
3255
|
useBrokerPublish(hookOptions?)
|
|
3016
3256
|
→ { mutate({ topic, message, headers?, key? }), isLoading, error, data }
|
|
3017
3257
|
useBrokerSubscription(subscribeOptions, hookOptions?)
|
|
3018
3258
|
→ { data: BrokerMessage[], isSubscribed, error, unsubscribe, resubscribe }
|
|
3019
|
-
subscribeOptions: { topic, group? }
|
|
3259
|
+
subscribeOptions: { broker?, topic, group?, session?, product?, env? }
|
|
3020
3260
|
|
|
3021
3261
|
GRAPH HOOKS
|
|
3022
3262
|
useGraph(graphTag) → { isConnected, isConnecting, error, connect, disconnect }
|
|
@@ -3086,7 +3326,10 @@ ACTIONS HOOKS
|
|
|
3086
3326
|
useActionRun(hookOptions?) → { mutate, isLoading, error, data }
|
|
3087
3327
|
|
|
3088
3328
|
ANALYTICS HOOK
|
|
3089
|
-
useAnalytics() → { pageview, track, identify }
|
|
3329
|
+
useAnalytics() → { pageview, track, identify, visitorId, enableAutoCapture, flush }
|
|
3330
|
+
The currently installed hook does NOT return clearSession or disableAutoCapture.
|
|
3331
|
+
Use useDuctape().client.analytics.clearSession()/disableAutoCapture(), or verify a newer installed
|
|
3332
|
+
package export before generating those hook calls. See ductape_docs({ topic: "frontend-analytics" }).
|
|
3090
3333
|
|
|
3091
3334
|
hookOptions pattern (applies to all hooks):
|
|
3092
3335
|
enabled? boolean — false skips auto-fetch/subscribe
|
|
@@ -3255,7 +3498,10 @@ ACTIONS COMPOSABLES
|
|
|
3255
3498
|
useActionRun(composableOptions?) → { mutate, isLoading, error, data }
|
|
3256
3499
|
|
|
3257
3500
|
ANALYTICS COMPOSABLE
|
|
3258
|
-
useAnalytics() → { pageview, track, identify }
|
|
3501
|
+
useAnalytics() → { pageview, track, identify, visitorId, enableAutoCapture, flush }
|
|
3502
|
+
The currently installed composable does NOT return clearSession or disableAutoCapture.
|
|
3503
|
+
Use useDuctape().client.analytics.clearSession()/disableAutoCapture(), or verify a newer installed
|
|
3504
|
+
package export before generating those composable calls. See ductape_docs({ topic: "frontend-analytics" }).
|
|
3259
3505
|
|
|
3260
3506
|
composableOptions pattern (applies to all composables):
|
|
3261
3507
|
enabled? boolean — false skips auto-fetch/subscribe
|
|
@@ -3598,7 +3844,7 @@ async function main() {
|
|
|
3598
3844
|
'index strategy, operation types) that should be confirmed with the user first.\n\n' +
|
|
3599
3845
|
'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
|
|
3600
3846
|
'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
|
|
3601
|
-
'notifications, resilience, features, events, logs, frontend, client, react, vue',
|
|
3847
|
+
'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue',
|
|
3602
3848
|
inputSchema: docsInputSchema,
|
|
3603
3849
|
}, docsHandler);
|
|
3604
3850
|
server.registerTool('ductape_cli', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ductape/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"description": "MCP server that exposes Ductape SDK operations via the backend proxy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
|
+
"test": "node scripts/check-frontend-analytics-guidance.mjs",
|
|
12
13
|
"start": "node dist/index.js",
|
|
13
14
|
"dev": "tsx src/index.ts"
|
|
14
15
|
},
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, resolve } from 'node:path';
|
|
5
|
+
|
|
6
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const source = readFileSync(resolve(here, '../src/index.ts'), 'utf8');
|
|
8
|
+
|
|
9
|
+
const checks = [
|
|
10
|
+
['dedicated docs topic', /'frontend-analytics': `/],
|
|
11
|
+
['anonymous analytics without an invented session', /Before login:[\s\S]*do not invent a session/i],
|
|
12
|
+
['identify after authentication', /After login\/registration:[\s\S]*identify\(fullSessionToken\)/i],
|
|
13
|
+
['identify after refresh', /After refresh:[\s\S]*identify\(newSessionToken\)/i],
|
|
14
|
+
['clear identity on logout and account switching', /LOGOUT \/ ACCOUNT SWITCHING[\s\S]*clearSession\(\)/],
|
|
15
|
+
['SPA route pageviews', /location\.pathname[\s\S]*analytics\.pageview/],
|
|
16
|
+
['pageviews and custom events', /CUSTOM EVENTS[\s\S]*PAGE VIEWS/],
|
|
17
|
+
['analytics is non-authoritative', /Analytics is never an authoritative order/],
|
|
18
|
+
['tokens excluded from properties', /session\/refresh tokens in event[\s\S]*properties/],
|
|
19
|
+
['hidden multiplayer state warning', /HIDDEN AND SENSITIVE DATA/],
|
|
20
|
+
['masking review before auto-capture', /AUTO-CAPTURE — OPT IN ONLY AFTER A PRIVACY AUDIT/],
|
|
21
|
+
['visitor ID is not authentication', /visitor ID is anonymous analytics identity, not authentication/i],
|
|
22
|
+
['trace correlation', /traceId\s*= correlation/],
|
|
23
|
+
['dashboard troubleshooting covers both tracks', /Investigate both tracks before blaming the SDK/],
|
|
24
|
+
['installed exports take precedence', /Installed package types and exports determine what can be called now/],
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
for (const [name, pattern] of checks) {
|
|
28
|
+
assert.match(source, pattern, `Missing frontend analytics guidance: ${name}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
assert.doesNotMatch(
|
|
32
|
+
source,
|
|
33
|
+
/analytics\.identify\(\{\s*userId/,
|
|
34
|
+
'MCP guidance must not use the obsolete identify({ userId, traits }) signature',
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
console.log(`frontend analytics guidance: ${checks.length + 1} acceptance checks passed`);
|
package/src/index.ts
CHANGED
|
@@ -1242,7 +1242,7 @@ const docsInputSchema = z.object({
|
|
|
1242
1242
|
'Feature topic to look up. Supported: ' +
|
|
1243
1243
|
'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
|
|
1244
1244
|
'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
|
|
1245
|
-
'notifications, resilience, features, events, logs, frontend, client, react, vue',
|
|
1245
|
+
'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue',
|
|
1246
1246
|
),
|
|
1247
1247
|
});
|
|
1248
1248
|
|
|
@@ -1280,6 +1280,11 @@ SHARED APPLICATION LIFECYCLE
|
|
|
1280
1280
|
connectionState to render disconnected/reconnecting UI; do not create duplicate subscriptions.
|
|
1281
1281
|
7. Disconnect resource sessions and the root client when the owning application scope is torn down.
|
|
1282
1282
|
|
|
1283
|
+
PRODUCT ANALYTICS
|
|
1284
|
+
Frontend product analytics complements backend session propagation; neither replaces the other.
|
|
1285
|
+
Continue with ductape_docs({ topic: "frontend-analytics" }) for identity lifecycle, pageviews,
|
|
1286
|
+
custom events, privacy masking, hidden-state safety, trace correlation, and package-version checks.
|
|
1287
|
+
|
|
1283
1288
|
AUTHENTICATION AND SECURITY
|
|
1284
1289
|
- Use publishableKey in browser applications. Never ship workspace private keys or privileged
|
|
1285
1290
|
access keys in frontend bundles.
|
|
@@ -2041,6 +2046,7 @@ Resource registration (all via ductape_cli or ductape_execute — see per-topic
|
|
|
2041
2046
|
caches → ductape_docs({ topic: "caches" })
|
|
2042
2047
|
notifications → ductape_docs({ topic: "notifications" })
|
|
2043
2048
|
sessions → ductape_docs({ topic: "sessions" })
|
|
2049
|
+
frontend analytics → ductape_docs({ topic: "frontend-analytics" })
|
|
2044
2050
|
resilience → ductape_docs({ topic: "resilience" })
|
|
2045
2051
|
features → ductape_docs({ topic: "features" })
|
|
2046
2052
|
|
|
@@ -2129,6 +2135,16 @@ Analytics:
|
|
|
2129
2135
|
|
|
2130
2136
|
Token format: "session_tag:jwt_token" — pass this format verbatim wherever session is expected.
|
|
2131
2137
|
JWT is signed with the product private key (not a symmetric shared secret).
|
|
2138
|
+
|
|
2139
|
+
SESSION PROPAGATION
|
|
2140
|
+
Preserve the original full token on every user-context database, Event, Feature, notification,
|
|
2141
|
+
storage, graph, vector, action, and other runtime operation that accepts session. Do not replace
|
|
2142
|
+
it with the session tag, user ID, decoded claims, or refresh token. Durable user-initiated work
|
|
2143
|
+
should retain the initiating token; intentional system/background work should be sessionless.
|
|
2144
|
+
|
|
2145
|
+
Backend propagation attributes component activity to an actor, but it does not record frontend
|
|
2146
|
+
pageviews, navigation, UI intent, funnels, or client failures. Continue immediately with
|
|
2147
|
+
ductape_docs({ topic: "frontend-analytics" }); both layers are required for a complete picture.
|
|
2132
2148
|
`.trim(),
|
|
2133
2149
|
|
|
2134
2150
|
caches: `
|
|
@@ -2296,6 +2312,223 @@ Input template references: $Input{field} → maps declared input to the probe's
|
|
|
2296
2312
|
Provider status: available | unavailable
|
|
2297
2313
|
`.trim(),
|
|
2298
2314
|
|
|
2315
|
+
'frontend-analytics': `
|
|
2316
|
+
DUCTAPE FRONTEND PRODUCT ANALYTICS AND SESSION ACTIVITY
|
|
2317
|
+
|
|
2318
|
+
Frontend analytics and backend session attribution are complementary; neither replaces the other.
|
|
2319
|
+
|
|
2320
|
+
BACKEND OPERATION ATTRIBUTION
|
|
2321
|
+
Pass the original full Ductape session token to every user-initiated database, Event, Feature,
|
|
2322
|
+
notification, storage, graph, vector, action, and other runtime operation that accepts session.
|
|
2323
|
+
This attributes server work to the authenticated actor. Durable work should retain the initiating
|
|
2324
|
+
session; intentional system/background work should remain sessionless.
|
|
2325
|
+
|
|
2326
|
+
FRONTEND PRODUCT ANALYTICS
|
|
2327
|
+
Use the browser Analytics service for anonymous visits, authenticated page views, navigation,
|
|
2328
|
+
UI interactions, funnels, client errors, realtime state, and product-surface engagement.
|
|
2329
|
+
|
|
2330
|
+
IMPORTANT:
|
|
2331
|
+
Passing session to backend component calls does not replace frontend analytics.
|
|
2332
|
+
Calling analytics.identify(sessionToken) and tracking frontend events does not replace backend
|
|
2333
|
+
session propagation. A complete activity picture requires both.
|
|
2334
|
+
|
|
2335
|
+
VERSION AND DOCUMENTATION PRECEDENCE
|
|
2336
|
+
1. Installed package types and exports determine what can be called now.
|
|
2337
|
+
2. Version-matched package documentation explains intended usage.
|
|
2338
|
+
3. Current docs/docs/Frontend describes the latest supported design.
|
|
2339
|
+
4. If they disagree, report the mismatch; never fabricate compatibility.
|
|
2340
|
+
|
|
2341
|
+
Inspect package.json plus package exports/type declarations before recommending framework hooks.
|
|
2342
|
+
The current repository exports useAnalytics from @ductape/react and @ductape/vue. Their installed
|
|
2343
|
+
hook/composable exposes track, pageview, identify, visitorId, enableAutoCapture, and flush.
|
|
2344
|
+
clearSession and disableAutoCapture are available on client.analytics but are not currently
|
|
2345
|
+
returned by those framework wrappers. Use useDuctape().client.analytics for those calls, or
|
|
2346
|
+
recommend a package version that exports them; do not generate a hook method that does not exist.
|
|
2347
|
+
|
|
2348
|
+
CLIENT API — IDENTIFY AFTER AUTHENTICATION
|
|
2349
|
+
ductape.analytics.identify(sessionToken);
|
|
2350
|
+
|
|
2351
|
+
sessionToken is the complete value returned by Ductape, in "player-session:jwt" format.
|
|
2352
|
+
It is NOT a player ID, session tag, session ID, decoded claims, or refresh token.
|
|
2353
|
+
identify links subsequent frontend analytics to the authenticated Ductape session and lets
|
|
2354
|
+
supported analytics correlate anonymous pre-login activity with authenticated activity.
|
|
2355
|
+
|
|
2356
|
+
LOGOUT / ACCOUNT SWITCHING
|
|
2357
|
+
await ductape.analytics.flush();
|
|
2358
|
+
ductape.analytics.clearSession();
|
|
2359
|
+
|
|
2360
|
+
Clear analytics identity when logout or revocation succeeds, refresh fails irrecoverably, local
|
|
2361
|
+
authentication is removed, or a different user is about to authenticate in the same browser.
|
|
2362
|
+
Removing only the application token can leave later anonymous/next-user events associated with
|
|
2363
|
+
the previous analytics identity. Flush is best-effort; browser shutdown does not guarantee it.
|
|
2364
|
+
|
|
2365
|
+
CUSTOM EVENTS
|
|
2366
|
+
await ductape.analytics.track({
|
|
2367
|
+
event: 'order_submitted',
|
|
2368
|
+
traceId,
|
|
2369
|
+
properties: { matchId, orderType },
|
|
2370
|
+
});
|
|
2371
|
+
|
|
2372
|
+
IAnalyticsTrackOptions:
|
|
2373
|
+
event: string
|
|
2374
|
+
properties?: Record<string, unknown>
|
|
2375
|
+
session?: string
|
|
2376
|
+
product?: string
|
|
2377
|
+
env?: string
|
|
2378
|
+
traceId?: string
|
|
2379
|
+
context?: { url?, path?, referrer?, locale?, screen?: { width, height } }
|
|
2380
|
+
|
|
2381
|
+
identify establishes the default analytics session. An individual event may explicitly provide
|
|
2382
|
+
session. Normally use product/env from client configuration. traceId correlates frontend intent
|
|
2383
|
+
with backend logs, Events, Features, and order processing.
|
|
2384
|
+
|
|
2385
|
+
PAGE VIEWS
|
|
2386
|
+
await ductape.analytics.pageview({
|
|
2387
|
+
path: location.pathname,
|
|
2388
|
+
title: document.title,
|
|
2389
|
+
properties: { matchId, screen: 'governance' },
|
|
2390
|
+
});
|
|
2391
|
+
|
|
2392
|
+
IAnalyticsPageviewOptions:
|
|
2393
|
+
path?: string
|
|
2394
|
+
title?: string
|
|
2395
|
+
session?: string
|
|
2396
|
+
product?: string
|
|
2397
|
+
env?: string
|
|
2398
|
+
properties?: Record<string, unknown>
|
|
2399
|
+
|
|
2400
|
+
AUTO-CAPTURE — OPT IN ONLY AFTER A PRIVACY AUDIT
|
|
2401
|
+
const stopAutoCapture = ductape.analytics.enableAutoCapture({
|
|
2402
|
+
session: () => authSession?.token,
|
|
2403
|
+
clicks: false,
|
|
2404
|
+
pageviews: true,
|
|
2405
|
+
maskTextSelectors: [
|
|
2406
|
+
'[data-private]',
|
|
2407
|
+
'[data-secret]',
|
|
2408
|
+
'[data-player-message]',
|
|
2409
|
+
'[data-intelligence-report]',
|
|
2410
|
+
],
|
|
2411
|
+
});
|
|
2412
|
+
stopAutoCapture(); // or ductape.analytics.disableAutoCapture()
|
|
2413
|
+
|
|
2414
|
+
Mark sensitive UI with data-private/data-secret attributes. Text masking may not mask attributes,
|
|
2415
|
+
IDs, URLs, element names, custom properties, console errors, or network errors. Inspect actual
|
|
2416
|
+
payloads before production. For hidden-information products, begin with reviewed automatic
|
|
2417
|
+
pageviews, clicks disabled, and preferred custom named events.
|
|
2418
|
+
|
|
2419
|
+
VISITOR ID
|
|
2420
|
+
const visitorId = ductape.analytics.getVisitorId();
|
|
2421
|
+
A visitor ID is anonymous analytics identity, not authentication or authorization.
|
|
2422
|
+
|
|
2423
|
+
FRONTEND SESSION LIFECYCLE
|
|
2424
|
+
Before login:
|
|
2425
|
+
- Track anonymous pageviews/onboarding; do not invent a session.
|
|
2426
|
+
After login/registration:
|
|
2427
|
+
- Store the session securely, identify(fullSessionToken), track success, start authenticated
|
|
2428
|
+
pageviews, and pass the same token to user-context realtime/component operations.
|
|
2429
|
+
After refresh:
|
|
2430
|
+
- Replace the old token, identify(newSessionToken), update realtime connections/subscriptions,
|
|
2431
|
+
and use the refreshed token for future backend operations.
|
|
2432
|
+
Logout:
|
|
2433
|
+
- Optionally track logout_initiated, flush, revoke, disconnect realtime, clearSession, then
|
|
2434
|
+
remove local authentication.
|
|
2435
|
+
Refresh failure/revocation:
|
|
2436
|
+
- Disconnect user-context clients, clearSession, clear local auth, navigate to authentication,
|
|
2437
|
+
and track only anonymous events afterward.
|
|
2438
|
+
|
|
2439
|
+
REACT ROUTE TRACKING (verify installed exports first)
|
|
2440
|
+
import { useAnalytics, useDuctape } from '@ductape/react';
|
|
2441
|
+
import { useEffect } from 'react';
|
|
2442
|
+
import { useLocation } from 'react-router-dom';
|
|
2443
|
+
|
|
2444
|
+
function ProductAnalytics({ sessionToken }: { sessionToken?: string }) {
|
|
2445
|
+
const analytics = useAnalytics();
|
|
2446
|
+
const { client } = useDuctape();
|
|
2447
|
+
const location = useLocation();
|
|
2448
|
+
useEffect(() => {
|
|
2449
|
+
if (sessionToken) analytics.identify(sessionToken);
|
|
2450
|
+
else client.analytics.clearSession();
|
|
2451
|
+
}, [analytics, client, sessionToken]);
|
|
2452
|
+
useEffect(() => {
|
|
2453
|
+
void analytics.pageview({ path: location.pathname, title: document.title });
|
|
2454
|
+
}, [analytics, location.pathname]);
|
|
2455
|
+
return null;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
SAFE EVENT TAXONOMY
|
|
2459
|
+
Define stable names centrally; do not invent variants throughout components.
|
|
2460
|
+
Authentication:
|
|
2461
|
+
registration_started, registration_completed, registration_failed,
|
|
2462
|
+
login_started, login_completed, login_failed, session_refreshed,
|
|
2463
|
+
session_refresh_failed, logout_completed
|
|
2464
|
+
Match:
|
|
2465
|
+
match_list_viewed, match_creation_started, match_created, match_joined, lobby_viewed,
|
|
2466
|
+
player_marked_ready, match_preparation_started, world_loaded, match_reconnected,
|
|
2467
|
+
match_completed, endgame_viewed
|
|
2468
|
+
Orders:
|
|
2469
|
+
order_form_opened, order_previewed, order_submission_started, order_submitted,
|
|
2470
|
+
order_submission_failed, order_cancelled, boundary_result_viewed
|
|
2471
|
+
Realtime:
|
|
2472
|
+
realtime_connect_started, realtime_connected, realtime_disconnected,
|
|
2473
|
+
realtime_reconnect_attempted, realtime_subscription_failed, projection_refresh_failed,
|
|
2474
|
+
client_error
|
|
2475
|
+
Funnels:
|
|
2476
|
+
tutorial_started, tutorial_step_completed, tutorial_abandoned, first_match_created,
|
|
2477
|
+
first_order_submitted, first_boundary_viewed, first_match_completed
|
|
2478
|
+
|
|
2479
|
+
Safe properties include matchId, orderType, screen, tick, result, and errorCategory.
|
|
2480
|
+
|
|
2481
|
+
HIDDEN AND SENSITIVE DATA — NEVER SEND TO ANALYTICS
|
|
2482
|
+
Do not track exact hidden formations, operative/handler identities, secret operation payloads,
|
|
2483
|
+
false-report truth markers, undiscovered evasion details, invisible treaties, canonical hidden
|
|
2484
|
+
map state, private messages, passwords, authorization headers, session/refresh tokens in event
|
|
2485
|
+
properties, or full errors/records that may contain secrets. Analytics must observe usage, not
|
|
2486
|
+
become a hidden-state side channel.
|
|
2487
|
+
|
|
2488
|
+
CORRELATION
|
|
2489
|
+
Frontend: create traceId = crypto.randomUUID(), track intent with traceId, and send traceId with
|
|
2490
|
+
the actual request. Backend logs the same traceId and propagates session to Ductape operations.
|
|
2491
|
+
Track completion with the same traceId.
|
|
2492
|
+
|
|
2493
|
+
traceId = correlation
|
|
2494
|
+
session = actor attribution
|
|
2495
|
+
idempotencyKey = duplicate prevention
|
|
2496
|
+
matchId/orderId = domain identity
|
|
2497
|
+
These values are not interchangeable.
|
|
2498
|
+
|
|
2499
|
+
OWNERSHIP BOUNDARIES
|
|
2500
|
+
Analytics is never an authoritative order, authorization proof, or gameplay source of truth.
|
|
2501
|
+
Analytics failure must not block or alter gameplay. The server verifies sessions independently;
|
|
2502
|
+
authoritative database and Event streams remain the source of truth. Prefer non-blocking
|
|
2503
|
+
analytics except explicit best-effort flushes at safe lifecycle transitions.
|
|
2504
|
+
|
|
2505
|
+
FRONTEND PROJECT AUDIT
|
|
2506
|
+
Inspect installed @ductape/client/react/vue versions and actual exports; client/provider setup;
|
|
2507
|
+
identify after login and refresh; clearSession on logout/account switch; SPA pageviews; auto-
|
|
2508
|
+
capture and masking; taxonomy consistency; sensitive custom properties; and shared trace IDs.
|
|
2509
|
+
Report capability as Present/Missing/Partial/Not applicable with concrete findings.
|
|
2510
|
+
|
|
2511
|
+
WHEN “SESSION ACTIVITY IS MISSING FROM THE DASHBOARD”
|
|
2512
|
+
Investigate both tracks before blaming the SDK.
|
|
2513
|
+
Backend: start/verify format, correct env, session on database/Event/Feature/notification/etc.,
|
|
2514
|
+
and intentional background sessionlessness.
|
|
2515
|
+
Frontend: identify after login/refresh, clearSession on logout, pageviews/custom events, flush,
|
|
2516
|
+
correct publishable key/product/env, installed API compatibility, browser failures, and privacy
|
|
2517
|
+
controls that may suppress events.
|
|
2518
|
+
|
|
2519
|
+
PAYLOAD RECIPES
|
|
2520
|
+
Anonymous:
|
|
2521
|
+
await ductape.analytics.pageview({ path: window.location.pathname, title: document.title });
|
|
2522
|
+
Authenticated:
|
|
2523
|
+
ductape.analytics.identify(playerSessionToken);
|
|
2524
|
+
await ductape.analytics.track({
|
|
2525
|
+
event: 'match_created', session: playerSessionToken, traceId, properties: { matchId },
|
|
2526
|
+
});
|
|
2527
|
+
Logout:
|
|
2528
|
+
await ductape.analytics.flush();
|
|
2529
|
+
ductape.analytics.clearSession();
|
|
2530
|
+
`.trim(),
|
|
2531
|
+
|
|
2299
2532
|
features: `
|
|
2300
2533
|
DUCTAPE FEATURES
|
|
2301
2534
|
|
|
@@ -2983,9 +3216,15 @@ SESSIONS SERVICE
|
|
|
2983
3216
|
const { token } = await ductape.sessions.refresh({ refreshToken: '...' });
|
|
2984
3217
|
|
|
2985
3218
|
ANALYTICS SERVICE
|
|
2986
|
-
ductape.analytics.
|
|
2987
|
-
ductape.analytics.
|
|
2988
|
-
ductape.analytics.
|
|
3219
|
+
ductape.analytics.identify('player-session:eyJ...'); // full Ductape session token
|
|
3220
|
+
await ductape.analytics.pageview({ path: '/dashboard', title: document.title });
|
|
3221
|
+
await ductape.analytics.track({
|
|
3222
|
+
event: 'button_clicked',
|
|
3223
|
+
properties: { button: 'sign-up' },
|
|
3224
|
+
});
|
|
3225
|
+
await ductape.analytics.flush();
|
|
3226
|
+
ductape.analytics.clearSession(); // logout/account switch
|
|
3227
|
+
See ductape_docs({ topic: "frontend-analytics" }) before enabling auto-capture.
|
|
2989
3228
|
|
|
2990
3229
|
FRAMEWORK-SPECIFIC PACKAGES
|
|
2991
3230
|
For React and Vue projects, use the dedicated packages instead of managing the client manually:
|
|
@@ -3087,13 +3326,15 @@ AGENT HOOKS
|
|
|
3087
3326
|
useAgentSignal(hookOptions?) → { mutate, isLoading, error }
|
|
3088
3327
|
|
|
3089
3328
|
BROKER HOOKS
|
|
3090
|
-
useBroker(
|
|
3329
|
+
useBroker()
|
|
3091
3330
|
→ { isConnected, isConnecting, error, connect, disconnect }
|
|
3331
|
+
connect({ broker, session?, product?, env? }) forwards the complete options object to
|
|
3332
|
+
@ductape/client. Pass session for player-scoped authorization.
|
|
3092
3333
|
useBrokerPublish(hookOptions?)
|
|
3093
3334
|
→ { mutate({ topic, message, headers?, key? }), isLoading, error, data }
|
|
3094
3335
|
useBrokerSubscription(subscribeOptions, hookOptions?)
|
|
3095
3336
|
→ { data: BrokerMessage[], isSubscribed, error, unsubscribe, resubscribe }
|
|
3096
|
-
subscribeOptions: { topic, group? }
|
|
3337
|
+
subscribeOptions: { broker?, topic, group?, session?, product?, env? }
|
|
3097
3338
|
|
|
3098
3339
|
GRAPH HOOKS
|
|
3099
3340
|
useGraph(graphTag) → { isConnected, isConnecting, error, connect, disconnect }
|
|
@@ -3163,7 +3404,10 @@ ACTIONS HOOKS
|
|
|
3163
3404
|
useActionRun(hookOptions?) → { mutate, isLoading, error, data }
|
|
3164
3405
|
|
|
3165
3406
|
ANALYTICS HOOK
|
|
3166
|
-
useAnalytics() → { pageview, track, identify }
|
|
3407
|
+
useAnalytics() → { pageview, track, identify, visitorId, enableAutoCapture, flush }
|
|
3408
|
+
The currently installed hook does NOT return clearSession or disableAutoCapture.
|
|
3409
|
+
Use useDuctape().client.analytics.clearSession()/disableAutoCapture(), or verify a newer installed
|
|
3410
|
+
package export before generating those hook calls. See ductape_docs({ topic: "frontend-analytics" }).
|
|
3167
3411
|
|
|
3168
3412
|
hookOptions pattern (applies to all hooks):
|
|
3169
3413
|
enabled? boolean — false skips auto-fetch/subscribe
|
|
@@ -3333,7 +3577,10 @@ ACTIONS COMPOSABLES
|
|
|
3333
3577
|
useActionRun(composableOptions?) → { mutate, isLoading, error, data }
|
|
3334
3578
|
|
|
3335
3579
|
ANALYTICS COMPOSABLE
|
|
3336
|
-
useAnalytics() → { pageview, track, identify }
|
|
3580
|
+
useAnalytics() → { pageview, track, identify, visitorId, enableAutoCapture, flush }
|
|
3581
|
+
The currently installed composable does NOT return clearSession or disableAutoCapture.
|
|
3582
|
+
Use useDuctape().client.analytics.clearSession()/disableAutoCapture(), or verify a newer installed
|
|
3583
|
+
package export before generating those composable calls. See ductape_docs({ topic: "frontend-analytics" }).
|
|
3337
3584
|
|
|
3338
3585
|
composableOptions pattern (applies to all composables):
|
|
3339
3586
|
enabled? boolean — false skips auto-fetch/subscribe
|
|
@@ -3732,7 +3979,7 @@ async function main() {
|
|
|
3732
3979
|
'index strategy, operation types) that should be confirmed with the user first.\n\n' +
|
|
3733
3980
|
'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
|
|
3734
3981
|
'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
|
|
3735
|
-
'notifications, resilience, features, events, logs, frontend, client, react, vue',
|
|
3982
|
+
'notifications, resilience, features, events, logs, frontend, frontend-analytics, client, react, vue',
|
|
3736
3983
|
inputSchema: docsInputSchema,
|
|
3737
3984
|
},
|
|
3738
3985
|
docsHandler,
|