@datatechsolutions/ui 3.1.0 → 3.2.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/dist/platform/telemetry/index.d.mts +12 -3
- package/dist/platform/telemetry/index.d.ts +12 -3
- package/dist/platform/telemetry/index.js +23 -2
- package/dist/platform/telemetry/index.js.map +1 -1
- package/dist/platform/telemetry/index.mjs +23 -2
- package/dist/platform/telemetry/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -14,9 +14,18 @@ type TelemetryUser = {
|
|
|
14
14
|
type TelemetryProviderProps = {
|
|
15
15
|
/** App slug — e.g. `astrlabe`, `sextant`, `data-br`. Tags every event. */
|
|
16
16
|
app: string;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* PostHog project token (write-only key, safe in browser bundles).
|
|
19
|
+
* If unset, the provider falls back to `window.__APP_CONFIG__.posthog.key`
|
|
20
|
+
* (set by the CDK-managed `runtime-config.js`) and then to
|
|
21
|
+
* `import.meta.env.VITE_POSTHOG_KEY`. Pass explicitly only for tests
|
|
22
|
+
* or sub-app embeds.
|
|
23
|
+
*/
|
|
18
24
|
projectKey?: string;
|
|
19
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* PostHog ingestion host. Falls back through the same chain as
|
|
27
|
+
* `projectKey`; defaults to US Cloud if nothing else resolves.
|
|
28
|
+
*/
|
|
20
29
|
apiHost?: string;
|
|
21
30
|
/** Whether to record session replays. Defaults to true. */
|
|
22
31
|
recordSessions?: boolean;
|
|
@@ -29,7 +38,7 @@ type TelemetryProviderProps = {
|
|
|
29
38
|
* PostHog associates events with the right tenant; pass `null` after
|
|
30
39
|
* sign-out so the next session is anonymous.
|
|
31
40
|
*/
|
|
32
|
-
declare function TelemetryProvider({ app, projectKey, apiHost, recordSessions, user, children, }: TelemetryProviderProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
declare function TelemetryProvider({ app, projectKey: propProjectKey, apiHost: propApiHost, recordSessions, user, children, }: TelemetryProviderProps): react_jsx_runtime.JSX.Element;
|
|
33
42
|
/**
|
|
34
43
|
* Re-export the posthog-js/react hook so consumer SPAs can capture
|
|
35
44
|
* custom events without importing posthog-js directly:
|
|
@@ -14,9 +14,18 @@ type TelemetryUser = {
|
|
|
14
14
|
type TelemetryProviderProps = {
|
|
15
15
|
/** App slug — e.g. `astrlabe`, `sextant`, `data-br`. Tags every event. */
|
|
16
16
|
app: string;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* PostHog project token (write-only key, safe in browser bundles).
|
|
19
|
+
* If unset, the provider falls back to `window.__APP_CONFIG__.posthog.key`
|
|
20
|
+
* (set by the CDK-managed `runtime-config.js`) and then to
|
|
21
|
+
* `import.meta.env.VITE_POSTHOG_KEY`. Pass explicitly only for tests
|
|
22
|
+
* or sub-app embeds.
|
|
23
|
+
*/
|
|
18
24
|
projectKey?: string;
|
|
19
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* PostHog ingestion host. Falls back through the same chain as
|
|
27
|
+
* `projectKey`; defaults to US Cloud if nothing else resolves.
|
|
28
|
+
*/
|
|
20
29
|
apiHost?: string;
|
|
21
30
|
/** Whether to record session replays. Defaults to true. */
|
|
22
31
|
recordSessions?: boolean;
|
|
@@ -29,7 +38,7 @@ type TelemetryProviderProps = {
|
|
|
29
38
|
* PostHog associates events with the right tenant; pass `null` after
|
|
30
39
|
* sign-out so the next session is anonymous.
|
|
31
40
|
*/
|
|
32
|
-
declare function TelemetryProvider({ app, projectKey, apiHost, recordSessions, user, children, }: TelemetryProviderProps): react_jsx_runtime.JSX.Element;
|
|
41
|
+
declare function TelemetryProvider({ app, projectKey: propProjectKey, apiHost: propApiHost, recordSessions, user, children, }: TelemetryProviderProps): react_jsx_runtime.JSX.Element;
|
|
33
42
|
/**
|
|
34
43
|
* Re-export the posthog-js/react hook so consumer SPAs can capture
|
|
35
44
|
* custom events without importing posthog-js directly:
|
|
@@ -12,14 +12,35 @@ var posthog__default = /*#__PURE__*/_interopDefault(posthog);
|
|
|
12
12
|
|
|
13
13
|
// src/platform/telemetry/posthog-provider.tsx
|
|
14
14
|
var DEFAULT_API_HOST = "https://us.i.posthog.com";
|
|
15
|
+
function resolveConfig(propKey, propHost) {
|
|
16
|
+
let key = propKey ?? "";
|
|
17
|
+
let host = propHost ?? "";
|
|
18
|
+
if (typeof window !== "undefined") {
|
|
19
|
+
const runtime = window.__APP_CONFIG__?.posthog;
|
|
20
|
+
if (!key && runtime?.key) key = runtime.key;
|
|
21
|
+
if (!host && runtime?.host) host = runtime.host;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const env = undefined ?? {};
|
|
25
|
+
if (!key) key = env.VITE_POSTHOG_KEY ?? "";
|
|
26
|
+
if (!host) host = env.VITE_POSTHOG_HOST ?? "";
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
if (!host) host = DEFAULT_API_HOST;
|
|
30
|
+
return { key, host };
|
|
31
|
+
}
|
|
15
32
|
function TelemetryProvider({
|
|
16
33
|
app,
|
|
17
|
-
projectKey,
|
|
18
|
-
apiHost
|
|
34
|
+
projectKey: propProjectKey,
|
|
35
|
+
apiHost: propApiHost,
|
|
19
36
|
recordSessions = true,
|
|
20
37
|
user,
|
|
21
38
|
children
|
|
22
39
|
}) {
|
|
40
|
+
const { key: projectKey, host: apiHost } = react$1.useMemo(
|
|
41
|
+
() => resolveConfig(propProjectKey, propApiHost),
|
|
42
|
+
[propProjectKey, propApiHost]
|
|
43
|
+
);
|
|
23
44
|
const enabled = react$1.useMemo(() => {
|
|
24
45
|
if (!projectKey) return false;
|
|
25
46
|
if (typeof window === "undefined") return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/platform/telemetry/posthog-provider.tsx"],"names":["useMemo","useEffect","posthog","jsx","Fragment","PostHogProvider","usePostHog"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../../../src/platform/telemetry/posthog-provider.tsx"],"names":["useMemo","useEffect","posthog","jsx","Fragment","PostHogProvider","usePostHog"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PostHog telemetry provider.\n *\n * Mounted once at the root of every Datatech SPA (astrlabe, sextant,\n * data-br, kori-erp, windsock-ui). Reads the PostHog project key + host\n * from `window.__APP_CONFIG__.posthog` — populated by `runtime-config.js`\n * which the deployed SPA's index.html loads BEFORE main.tsx. The CDK\n * FrontendStack uploads `runtime-config.js` to the bucket from SSM\n * (`/datatech/{env}/posthog/{project-key,api-host}`).\n *\n * For local dev, `import.meta.env.VITE_POSTHOG_KEY` is the fallback —\n * empty in most local sessions, so telemetry stays off without ceremony.\n *\n * Explicit prop overrides (`projectKey` / `apiHost`) win over both —\n * useful for tests and one-off sub-app embeds.\n *\n * Why a shared provider instead of per-app posthog.init():\n * - Single bundle dep (peer-installed in each SPA, but the wiring\n * code lives here so identification + opt-out logic stays consistent).\n * - Auto-tags every event with `app` (SPA name) and `organization_id`\n * (windsock JWT claim) so analytics across the platform can pivot\n * by tenant without per-team plumbing.\n *\n * Opt-out:\n * - Tracking disabled if no project key is resolvable from any source.\n * - Tracking disabled if `localStorage.posthog_opt_out === 'true'`.\n * - Replay can be disabled separately via `recordSessions={false}`.\n */\nimport posthog from 'posthog-js'\nimport { PostHogProvider, usePostHog } from 'posthog-js/react'\nimport { type ReactNode, useEffect, useMemo } from 'react'\n\nexport type TelemetryUser = {\n /** Stable user id — typically the windsock JWT `sub`. */\n id: string\n email?: string\n name?: string\n role?: string\n /** Tenant id — from `https://datatechsolutions.com.br/organization_id` claim. */\n organizationId?: string\n}\n\nexport type TelemetryProviderProps = {\n /** App slug — e.g. `astrlabe`, `sextant`, `data-br`. Tags every event. */\n app: string\n /**\n * PostHog project token (write-only key, safe in browser bundles).\n * If unset, the provider falls back to `window.__APP_CONFIG__.posthog.key`\n * (set by the CDK-managed `runtime-config.js`) and then to\n * `import.meta.env.VITE_POSTHOG_KEY`. Pass explicitly only for tests\n * or sub-app embeds.\n */\n projectKey?: string\n /**\n * PostHog ingestion host. Falls back through the same chain as\n * `projectKey`; defaults to US Cloud if nothing else resolves.\n */\n apiHost?: string\n /** Whether to record session replays. Defaults to true. */\n recordSessions?: boolean\n /** Current authenticated user, if any. The provider re-identifies on change. */\n user?: TelemetryUser | null\n children: ReactNode\n}\n\nconst DEFAULT_API_HOST = 'https://us.i.posthog.com'\n\n/**\n * Resolve the PostHog config from the first source that has a value:\n * 1. Explicit prop (test override)\n * 2. `window.__APP_CONFIG__.posthog.{key,host}` (deployed runtime-config.js)\n * 3. `import.meta.env.VITE_POSTHOG_*` (local dev)\n */\nfunction resolveConfig(propKey?: string, propHost?: string): { key: string; host: string } {\n let key = propKey ?? ''\n let host = propHost ?? ''\n\n if (typeof window !== 'undefined') {\n const runtime = (window as unknown as { __APP_CONFIG__?: { posthog?: { key?: string; host?: string } } })\n .__APP_CONFIG__?.posthog\n if (!key && runtime?.key) key = runtime.key\n if (!host && runtime?.host) host = runtime.host\n }\n\n // Vite injects `import.meta.env.*` at build time; reading is safe in\n // both dev and prod bundles. Empty string when not defined.\n try {\n const env = (import.meta as unknown as { env?: Record<string, string | undefined> }).env ?? {}\n if (!key) key = env.VITE_POSTHOG_KEY ?? ''\n if (!host) host = env.VITE_POSTHOG_HOST ?? ''\n } catch {\n /* import.meta unavailable (CJS test env) — treat as no env */\n }\n\n if (!host) host = DEFAULT_API_HOST\n return { key, host }\n}\n\n/**\n * Wrap every SPA in this provider. Pass the windsock-resolved user so\n * PostHog associates events with the right tenant; pass `null` after\n * sign-out so the next session is anonymous.\n */\nexport function TelemetryProvider({\n app,\n projectKey: propProjectKey,\n apiHost: propApiHost,\n recordSessions = true,\n user,\n children,\n}: TelemetryProviderProps) {\n const { key: projectKey, host: apiHost } = useMemo(\n () => resolveConfig(propProjectKey, propApiHost),\n [propProjectKey, propApiHost],\n )\n\n const enabled = useMemo(() => {\n if (!projectKey) return false\n if (typeof window === 'undefined') return false\n if (window.localStorage?.getItem('posthog_opt_out') === 'true') return false\n return true\n }, [projectKey])\n\n useEffect(() => {\n if (!enabled || !projectKey) return\n // Idempotent — posthog.init no-ops on second call with same key.\n posthog.init(projectKey, {\n api_host: apiHost,\n defaults: '2026-01-30',\n // Session replay: capture DOM + console + network (excluding\n // request/response bodies — PII risk). The masking config blanks\n // input fields by default; sensitive forms (login, MFA) should\n // mark themselves with `data-ph-no-capture` to be extra-safe.\n session_recording: recordSessions\n ? {\n maskAllInputs: true,\n recordCrossOriginIframes: false,\n }\n : undefined,\n capture_pageview: 'history_change',\n capture_pageleave: true,\n autocapture: true,\n // Always tag every event with the SPA slug so we can filter.\n loaded: (instance) => {\n instance.register({ app })\n },\n })\n }, [enabled, projectKey, apiHost, recordSessions, app])\n\n useEffect(() => {\n if (!enabled) return\n if (user?.id) {\n posthog.identify(user.id, {\n email: user.email,\n name: user.name,\n role: user.role,\n organization_id: user.organizationId,\n })\n if (user.organizationId) {\n posthog.group('organization', user.organizationId)\n }\n } else {\n // No user (sign-out, never authenticated) → reset PostHog identity\n // so the next sign-in starts a fresh session.\n posthog.reset()\n }\n }, [enabled, user?.id, user?.email, user?.name, user?.role, user?.organizationId])\n\n if (!enabled) return <>{children}</>\n\n return <PostHogProvider client={posthog}>{children}</PostHogProvider>\n}\n\n/**\n * Re-export the posthog-js/react hook so consumer SPAs can capture\n * custom events without importing posthog-js directly:\n *\n * const ph = useTelemetry()\n * ph?.capture('workflow_run_started', { workflowId })\n */\nexport const useTelemetry = usePostHog\n"]}
|
|
@@ -6,14 +6,35 @@ import { jsx, Fragment } from 'react/jsx-runtime';
|
|
|
6
6
|
|
|
7
7
|
// src/platform/telemetry/posthog-provider.tsx
|
|
8
8
|
var DEFAULT_API_HOST = "https://us.i.posthog.com";
|
|
9
|
+
function resolveConfig(propKey, propHost) {
|
|
10
|
+
let key = propKey ?? "";
|
|
11
|
+
let host = propHost ?? "";
|
|
12
|
+
if (typeof window !== "undefined") {
|
|
13
|
+
const runtime = window.__APP_CONFIG__?.posthog;
|
|
14
|
+
if (!key && runtime?.key) key = runtime.key;
|
|
15
|
+
if (!host && runtime?.host) host = runtime.host;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const env = import.meta.env ?? {};
|
|
19
|
+
if (!key) key = env.VITE_POSTHOG_KEY ?? "";
|
|
20
|
+
if (!host) host = env.VITE_POSTHOG_HOST ?? "";
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
if (!host) host = DEFAULT_API_HOST;
|
|
24
|
+
return { key, host };
|
|
25
|
+
}
|
|
9
26
|
function TelemetryProvider({
|
|
10
27
|
app,
|
|
11
|
-
projectKey,
|
|
12
|
-
apiHost
|
|
28
|
+
projectKey: propProjectKey,
|
|
29
|
+
apiHost: propApiHost,
|
|
13
30
|
recordSessions = true,
|
|
14
31
|
user,
|
|
15
32
|
children
|
|
16
33
|
}) {
|
|
34
|
+
const { key: projectKey, host: apiHost } = useMemo(
|
|
35
|
+
() => resolveConfig(propProjectKey, propApiHost),
|
|
36
|
+
[propProjectKey, propApiHost]
|
|
37
|
+
);
|
|
17
38
|
const enabled = useMemo(() => {
|
|
18
39
|
if (!projectKey) return false;
|
|
19
40
|
if (typeof window === "undefined") return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/platform/telemetry/posthog-provider.tsx"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"sources":["../../../src/platform/telemetry/posthog-provider.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * PostHog telemetry provider.\n *\n * Mounted once at the root of every Datatech SPA (astrlabe, sextant,\n * data-br, kori-erp, windsock-ui). Reads the PostHog project key + host\n * from `window.__APP_CONFIG__.posthog` — populated by `runtime-config.js`\n * which the deployed SPA's index.html loads BEFORE main.tsx. The CDK\n * FrontendStack uploads `runtime-config.js` to the bucket from SSM\n * (`/datatech/{env}/posthog/{project-key,api-host}`).\n *\n * For local dev, `import.meta.env.VITE_POSTHOG_KEY` is the fallback —\n * empty in most local sessions, so telemetry stays off without ceremony.\n *\n * Explicit prop overrides (`projectKey` / `apiHost`) win over both —\n * useful for tests and one-off sub-app embeds.\n *\n * Why a shared provider instead of per-app posthog.init():\n * - Single bundle dep (peer-installed in each SPA, but the wiring\n * code lives here so identification + opt-out logic stays consistent).\n * - Auto-tags every event with `app` (SPA name) and `organization_id`\n * (windsock JWT claim) so analytics across the platform can pivot\n * by tenant without per-team plumbing.\n *\n * Opt-out:\n * - Tracking disabled if no project key is resolvable from any source.\n * - Tracking disabled if `localStorage.posthog_opt_out === 'true'`.\n * - Replay can be disabled separately via `recordSessions={false}`.\n */\nimport posthog from 'posthog-js'\nimport { PostHogProvider, usePostHog } from 'posthog-js/react'\nimport { type ReactNode, useEffect, useMemo } from 'react'\n\nexport type TelemetryUser = {\n /** Stable user id — typically the windsock JWT `sub`. */\n id: string\n email?: string\n name?: string\n role?: string\n /** Tenant id — from `https://datatechsolutions.com.br/organization_id` claim. */\n organizationId?: string\n}\n\nexport type TelemetryProviderProps = {\n /** App slug — e.g. `astrlabe`, `sextant`, `data-br`. Tags every event. */\n app: string\n /**\n * PostHog project token (write-only key, safe in browser bundles).\n * If unset, the provider falls back to `window.__APP_CONFIG__.posthog.key`\n * (set by the CDK-managed `runtime-config.js`) and then to\n * `import.meta.env.VITE_POSTHOG_KEY`. Pass explicitly only for tests\n * or sub-app embeds.\n */\n projectKey?: string\n /**\n * PostHog ingestion host. Falls back through the same chain as\n * `projectKey`; defaults to US Cloud if nothing else resolves.\n */\n apiHost?: string\n /** Whether to record session replays. Defaults to true. */\n recordSessions?: boolean\n /** Current authenticated user, if any. The provider re-identifies on change. */\n user?: TelemetryUser | null\n children: ReactNode\n}\n\nconst DEFAULT_API_HOST = 'https://us.i.posthog.com'\n\n/**\n * Resolve the PostHog config from the first source that has a value:\n * 1. Explicit prop (test override)\n * 2. `window.__APP_CONFIG__.posthog.{key,host}` (deployed runtime-config.js)\n * 3. `import.meta.env.VITE_POSTHOG_*` (local dev)\n */\nfunction resolveConfig(propKey?: string, propHost?: string): { key: string; host: string } {\n let key = propKey ?? ''\n let host = propHost ?? ''\n\n if (typeof window !== 'undefined') {\n const runtime = (window as unknown as { __APP_CONFIG__?: { posthog?: { key?: string; host?: string } } })\n .__APP_CONFIG__?.posthog\n if (!key && runtime?.key) key = runtime.key\n if (!host && runtime?.host) host = runtime.host\n }\n\n // Vite injects `import.meta.env.*` at build time; reading is safe in\n // both dev and prod bundles. Empty string when not defined.\n try {\n const env = (import.meta as unknown as { env?: Record<string, string | undefined> }).env ?? {}\n if (!key) key = env.VITE_POSTHOG_KEY ?? ''\n if (!host) host = env.VITE_POSTHOG_HOST ?? ''\n } catch {\n /* import.meta unavailable (CJS test env) — treat as no env */\n }\n\n if (!host) host = DEFAULT_API_HOST\n return { key, host }\n}\n\n/**\n * Wrap every SPA in this provider. Pass the windsock-resolved user so\n * PostHog associates events with the right tenant; pass `null` after\n * sign-out so the next session is anonymous.\n */\nexport function TelemetryProvider({\n app,\n projectKey: propProjectKey,\n apiHost: propApiHost,\n recordSessions = true,\n user,\n children,\n}: TelemetryProviderProps) {\n const { key: projectKey, host: apiHost } = useMemo(\n () => resolveConfig(propProjectKey, propApiHost),\n [propProjectKey, propApiHost],\n )\n\n const enabled = useMemo(() => {\n if (!projectKey) return false\n if (typeof window === 'undefined') return false\n if (window.localStorage?.getItem('posthog_opt_out') === 'true') return false\n return true\n }, [projectKey])\n\n useEffect(() => {\n if (!enabled || !projectKey) return\n // Idempotent — posthog.init no-ops on second call with same key.\n posthog.init(projectKey, {\n api_host: apiHost,\n defaults: '2026-01-30',\n // Session replay: capture DOM + console + network (excluding\n // request/response bodies — PII risk). The masking config blanks\n // input fields by default; sensitive forms (login, MFA) should\n // mark themselves with `data-ph-no-capture` to be extra-safe.\n session_recording: recordSessions\n ? {\n maskAllInputs: true,\n recordCrossOriginIframes: false,\n }\n : undefined,\n capture_pageview: 'history_change',\n capture_pageleave: true,\n autocapture: true,\n // Always tag every event with the SPA slug so we can filter.\n loaded: (instance) => {\n instance.register({ app })\n },\n })\n }, [enabled, projectKey, apiHost, recordSessions, app])\n\n useEffect(() => {\n if (!enabled) return\n if (user?.id) {\n posthog.identify(user.id, {\n email: user.email,\n name: user.name,\n role: user.role,\n organization_id: user.organizationId,\n })\n if (user.organizationId) {\n posthog.group('organization', user.organizationId)\n }\n } else {\n // No user (sign-out, never authenticated) → reset PostHog identity\n // so the next sign-in starts a fresh session.\n posthog.reset()\n }\n }, [enabled, user?.id, user?.email, user?.name, user?.role, user?.organizationId])\n\n if (!enabled) return <>{children}</>\n\n return <PostHogProvider client={posthog}>{children}</PostHogProvider>\n}\n\n/**\n * Re-export the posthog-js/react hook so consumer SPAs can capture\n * custom events without importing posthog-js directly:\n *\n * const ph = useTelemetry()\n * ph?.capture('workflow_run_started', { workflowId })\n */\nexport const useTelemetry = usePostHog\n"]}
|