Skip to content

feat(node): send transactional email from a template - #5418

Merged
mayteio merged 12 commits into
mainfrom
posthog/node-transactional-email-send
Oct 30, 2026
Merged

mayteio merged 12 commits into
mainfrom
posthog/node-transactional-email-send

Conversation

@mayteio

@mayteio mayteio commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Example

import { PostHog } from 'posthog-node'

const posthog = new PostHog('phc_...', {
    host: 'https://us.i.posthog.com',
    // A project secret API key with the hog_flow:write scope. Never ship it to a browser.
    secretKey: process.env.POSTHOG_SECRET_KEY,
    // Only when the key is for email and not for local flag evaluation.
    enableLocalEvaluation: false,
})

const { data, error } = await posthog.emails.send({
    to: user.email,
    templateId: '01a1598d-...', // the transactional template's ID, from its API tab
    templateData: { reset_link: resetLink },
    distinctId: user.id,
    idempotencyKey: `password-reset:${user.id}:${resetToken.id}`,
})

if (error) {
    // error.code is PostHog's code, such as recipient_suppressed or quota_limited
    logger.warn('Password reset email not sent', { code: error.code, message: error.message })
} else {
    // Queued, not yet delivered
    logger.info('Password reset email queued', { messageId: data.id })
}

// Later, for example from a job: queued, sent, failed, delivered, bounced or complained
const { data: status } = await posthog.emails.get(data.id)

Problem

Server-side apps want to send PostHog transactional emails with one call on the client they already have, matching posthog-python.

This is the Node side of the template form in the cross-SDK contract PostHog/posthog#120921, and mirrors PostHog/posthog-python#1093. The code-content form is out of scope. The send API is in beta on the server.

Changes

  • posthog.emails.send({ to, templateId, templateData?, distinctId?, idempotencyKey?, maxRetries? }) posts to {appHost}/api/projects/@current/messaging/send/email/ with the template ID as template.id, with Authorization: Bearer <secretKey> and an Idempotency-Key. templateData becomes message_data and distinctId becomes identifiers.distinct_id. The request context is never used for the recipient.
  • New client options: appHost, emailRequestTimeoutMs (default 15000) and emailRequestMaxRetries (default 2). The names follow the existing featureFlagsRequestTimeoutMs / featureFlagsRequestMaxRetries options, like python's email_request_*. secretKey already exists and is reused.
  • The client derives the app host for PostHog Cloud (us.i, eu.i, us, eu and app.posthog.com). For any other host, a send without appHost fails with missing_app_host before any request, because a custom host may be an ingestion proxy. A missing key fails with missing_secret_key, also before any request.
  • When the caller passes no idempotency key, the client generates a UUID v4 and sends it on every retry. Network errors, 409 idempotency_key_in_flight, 429 throttled and 503 are retried, with a backoff of about 1 s and then 2 s with jitter, or Retry-After when that is longer. A Retry-After over 30 s returns the error at once. 429 quota_limited and other 4xx responses are not retried. maxRetries: 0 turns retries off.
  • send resolves to { data, error } and does not reject. data is { id, replayed, warnings }. error is an EmailError. It carries PostHog's code as-is, so new server codes need no SDK change. It also carries a category name, message, statusCode, retryAfterMs, field (from attr), and why / fix / docsUrl when the server sends them.
  • A disabled client sends nothing and returns the error client_disabled, like python.
  • posthog.emails.get(id) reads {appHost}/api/projects/@current/messaging/emails/{id}/ and resolves to { data, error }. data is { id, status, createdAt, statusAt, reason }. It retries like send, which now shares that attempt loop. An unknown or expired ID returns not_found.
  • A key with hog_flow:write both sends and reads. A key with only hog_flow:read reads.

Important

Merge after PostHog/posthog#123932 (the status endpoint) and its writers PostHog/posthog#124736 and PostHog/posthog#124751 are deployed and EMAIL_STATUS_ENABLED is on. Until then get answers not_found for every email.

Why { data, error } rather than throwing

posthog-node's awaited request methods do not reject when a request fails. getFeatureFlag, getFeatureFlagPayload, evaluateFlags and getRemoteConfigPayload resolve with undefined or a fallback and report the failure on posthog.on('error'). PostHogFetchHttpError and PostHogFetchNetworkError are internal to core and never reach callers. Only flush() / shutdown() reject. No existing method returns structured error details to the caller. { data, error } keeps the "resolve, don't reject" convention and gives the caller what it needs to branch, which is what the contract asks for Node. The error is returned, not also emitted on on('error'), so it is not reported twice.

Differences from posthog-python#1093

  • It returns { data, error } instead of raising, as the contract specifies for Node.
  • Local argument checks return a validation_error with codes such as invalid_template_id or invalid_idempotency_key. Python raises TypeError / ValueError for these.
  • There is a per-send maxRetries, which the contract asks for.
  • There is no standalone Emails class and no client_closed state. Node clients have no email transport to close and stay usable after shutdown().

Note

Divergence from PostHog/posthog#120921: the contract's capture_engagement send option is not here yet. The template send endpoint this SDK calls does not accept it, so the option would be silently ignored. It lands with the server support.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • All commits are signed (see Commit signing)
  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Written by Claude Opus 5.5 (claude-opus-5-5) in a PostHog Desktop task, directed by the assignee.
  • src/__tests__/emails.spec.ts uses fake timers. It covers request shape, host derivation and the refused proxy host, a missing key, which responses are retried with the same key, Retry-After, the backoff timing, retry limits, the timeout, and argument checks. pnpm lint, pnpm check-types, the full posthog-node unit suite and test:edge-compat pass. References were regenerated.
  • Tested against a local PostHog dev stack with the status endpoint and its writers: a send landed in MailDev, get read it as sent, and an unknown ID returned not_found (404). Not tested against PostHog Cloud.
  • The retry sleep uses a ref'd timer, unlike the SDK's background timers, so a short script that awaits a send stays alive through a retry.

🤖 Generated with Claude Code


Created with PostHog Desktop

Add posthog.emails.send() for PostHog transactional email templates, with the appHost, emailRequestTimeoutMs and emailRequestMaxRetries client options. Sends go to the app host with the project secret key and an idempotency key that every retry reuses. send() resolves to { data, error }.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: a0274fa0-d9be-48bf-b601-f153decf241d
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Coherence

0 spec problems · 0 failing chokepoints · 2 spec gaps · 0 guard failures

44 components, 7 bullets (5 invariants, 2 requirements), 0 problems

Chokepoints: none declared.

Spec gaps: 2 entrances with outside or unknown trust and no traced control, and 10 more held by the adoption baseline

  • packages/web/Web.spec.md entrance public api (trust host-app): packages/web
  • packages/webpack-plugin/Webpack-plugin.spec.md entrance webpack plugin (trust build): packages/webpack-plugin

Close one with guard: <chokepoint>, an invariant that names it on its entrances: line, or control: none — <reason>; scaffold control proposes it.

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 65d7240: 3 Should fix.

This Standard review started from the posthog-review label. Comment @posthog review --deep for a Deep review, or @posthog help to see all commands.

See this review and its findings in PostHog Review.

Comment thread packages/node/src/emails/emails.ts Outdated

function readRetryAfter(response: PostHogFetchResponse): number | undefined {
try {
return parseRetryAfterMs(response.headers?.get('retry-after'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Preserve the full server Retry-After duration

When PostHog returns Retry-After: 3600, readRetryAfter returns 300000 ms because the shared parseRetryAfterMs caps values at five minutes. Consequently, error.retryAfterMs tells callers to retry 55 minutes early, breaking server-directed backoff in job runners. Parse the full duration for email errors and apply the retry ceiling separately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc3b6f6. readRetryAfter now passes a cap to parseRetryAfterMs (a new optional argument in @posthog/core), so error.retryAfterMs keeps the full server wait. The 30 second retry ceiling in retryDelayMs still applies separately. The existing "gives up at once on a Retry-After over 30 seconds" test now uses Retry-After: 3600 and expects 3600000 ms, which fails with the five minute cap.

Comment thread packages/node/src/emails/emails.ts Outdated
let timer: ReturnType<typeof safeSetTimeout>
// `fetch` is injectable and may ignore the abort signal, so both phases race the deadline.
const deadline = new Promise<never>((_resolve, reject) => {
timer = safeSetTimeout(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Keep the request deadline referenced until the send settles

When an injected fetch stalls without a referenced I/O handle, safeSetTimeout unrefs the only timer keeping request() alive. A short-lived Node script exits successfully while awaiting emails.send(), before the timeout fires or retries run, so callers never receive an error. Keep this deadline referenced with setTimeout, as the retry sleep already does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc3b6f6. The deadline uses a plain setTimeout instead of safeSetTimeout, so it stays referenced until the send settles, the same as the retry sleep. finally still clears it. No new test: an unref'd timer only changes whether a real process exits, and the suite runs on fake timers.

Comment thread packages/node/src/emails/emails.ts Outdated
if (!appHost) {
// A custom host is often an ingestion proxy, which must not receive the secret key.
throw new EmailError({
code: 'app_host_required',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Return the contractual missing_app_host error code

With a custom host and no appHost, send() returns app_host_required, but the cross-SDK contract in PostHog/posthog#120921 defines missing_app_host. Callers branching on that documented stable code miss this configuration error and fall through to generic error handling; return missing_app_host here.

@mayteio mayteio Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc3b6f6. A custom host without appHost now fails with missing_app_host, as PostHog/posthog#120921 defines. The test case is updated.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Node SDK acceptance v2

Commit: eb01f45
Workflow run and artifacts

Capture v0

✅ 55 passed / ❌ 1 non-passing / ⚠️ 101 not selected

Drill-down: run artifacts → node-v2-v0 → acceptance/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

Capture v1

✅ 120 passed / ❌ 1 non-passing / ⚠️ 36 not selected

Drill-down: run artifacts → node-v2-v1 → acceptance/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

- A custom host without appHost now fails with missing_app_host, the code the cross-SDK contract in PostHog/posthog#120921 defines.
- The request deadline uses a referenced timer, so a short-lived script can't exit while it awaits a send whose injected fetch holds no handle.
- error.retryAfterMs keeps the full server Retry-After. parseRetryAfterMs in @posthog/core takes an optional cap for this; the 30 second retry ceiling still applies separately.
- The email send responses entrance in Node.spec.md declares control: none with its reason, which closes the coherence spec gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Size Change: +37.1 kB (+0.15%)

Total Size: 25.3 MB

📦 View Changed
Filename Size Change
packages/browser-next/dist/analytics-********.js 8.79 kB +6.84 kB (+351.46%) 🆘
packages/browser-next/dist/analytics-********.mjs 273 B -6.84 kB (-96.16%) 🏆
packages/browser/dist/array.full.es5.js 546 kB +22 B (0%)
packages/browser/dist/array.full.js 681 kB +7 B (0%)
packages/browser/dist/array.full.no-********.js 747 kB +7 B (0%)
packages/browser/dist/array.js 338 kB +7 B (0%)
packages/browser/dist/array.no-********.js 384 kB +7 B (0%)
packages/browser/dist/default-extensions.js 336 kB +7 B (0%)
packages/browser/dist/main.js 343 kB +7 B (0%)
packages/browser/dist/module.full.cjs 685 kB +7 B (0%)
packages/browser/dist/module.full.js 685 kB +7 B (0%)
packages/browser/dist/module.full.no-********.cjs 752 kB +7 B (0%)
packages/browser/dist/module.full.no-********.js 751 kB +7 B (0%)
packages/browser/dist/module.js 342 kB +7 B (0%)
packages/browser/dist/module.mjs 342 kB +7 B (0%)
packages/browser/dist/module.no-********.cjs 388 kB +7 B (0%)
packages/browser/dist/module.no-********.js 388 kB +7 B (0%)
packages/browser/dist/module.slim.js 154 kB +22 B (+0.01%)
packages/browser/dist/module.slim.no-********.js 170 kB +22 B (+0.01%)
packages/core/dist/utils/retry-after.js 3.5 kB +2 B (+0.06%)
packages/core/dist/utils/retry-after.mjs 1.96 kB +2 B (+0.1%)
packages/node/dist/client.js 66.3 kB +1.5 kB (+2.32%)
packages/node/dist/client.mjs 62.5 kB +1.46 kB (+2.39%)
packages/node/dist/emails/emails.js 15.4 kB +15.4 kB (new file) 🆕
packages/node/dist/emails/emails.mjs 13.2 kB +13.2 kB (new file) 🆕
packages/node/dist/emails/errors.js 2.79 kB +2.79 kB (new file) 🆕
packages/node/dist/emails/errors.mjs 1.52 kB +1.52 kB (new file) 🆕
packages/node/dist/emails/types.js 585 B +585 B (new file) 🆕
packages/node/dist/emails/types.mjs 12 B +12 B (new file) 🆕
packages/node/dist/exports.js 7.2 kB +383 B (+5.62%) 🔍
packages/node/dist/exports.mjs 510 B +50 B (+10.87%) ⚠️
ℹ️ View Unchanged
Filename Size
packages/ai/dist/adk/index.cjs 41.8 kB
packages/ai/dist/adk/index.mjs 41.6 kB
packages/ai/dist/anthropic/index.cjs 47 kB
packages/ai/dist/anthropic/index.mjs 45.6 kB
packages/ai/dist/claude-agent-sdk/index.cjs 50.1 kB
packages/ai/dist/claude-agent-sdk/index.mjs 49.8 kB
packages/ai/dist/evaluations/index.cjs 59.1 kB
packages/ai/dist/evaluations/index.mjs 58.7 kB
packages/ai/dist/gemini/index.cjs 60.6 kB
packages/ai/dist/gemini/index.mjs 60.3 kB
packages/ai/dist/index.cjs 64.5 kB
packages/ai/dist/index.mjs 64.3 kB
packages/ai/dist/langchain/index.cjs 43.1 kB
packages/ai/dist/langchain/index.mjs 42.9 kB
packages/ai/dist/langchain/middleware/index.cjs 49.6 kB
packages/ai/dist/langchain/middleware/index.mjs 49.2 kB
packages/ai/dist/openai-agents/index.cjs 34.9 kB
packages/ai/dist/openai-agents/index.mjs 34.7 kB
packages/ai/dist/openai/index.cjs 90.8 kB
packages/ai/dist/openai/index.mjs 90.2 kB
packages/ai/dist/otel/index.cjs 27.5 kB
packages/ai/dist/otel/index.mjs 27.2 kB
packages/ai/dist/vercel/index.cjs 46.4 kB
packages/ai/dist/vercel/index.mjs 46.3 kB
packages/browser-common/dist/autocapture-config.js 585 B
packages/browser-common/dist/autocapture-config.mjs 12 B
packages/browser-common/dist/autocapture.js 29.9 kB
packages/browser-common/dist/autocapture.mjs 23.9 kB
packages/browser-common/dist/client.js 585 B
packages/browser-common/dist/client.mjs 12 B
packages/browser-common/dist/config.js 1.52 kB
packages/browser-common/dist/config.mjs 217 B
packages/browser-common/dist/console-logs.js 13 kB
packages/browser-common/dist/console-logs.mjs 11.3 kB
packages/browser-common/dist/constants.js 6.37 kB
packages/browser-common/dist/constants.mjs 1.94 kB
packages/browser-common/dist/disposable.js 1.72 kB
packages/browser-common/dist/disposable.mjs 386 B
packages/browser-common/dist/extension-runtime.js 3.17 kB
packages/browser-common/dist/extension-runtime.mjs 1.83 kB
packages/browser-common/dist/extension-tokens.js 1.44 kB
packages/browser-common/dist/extension-tokens.mjs 98 B
packages/browser-common/dist/extension.js 585 B
packages/browser-common/dist/extension.mjs 12 B
packages/browser-common/dist/feature-flags-config.js 585 B
packages/browser-common/dist/feature-flags-config.mjs 12 B
packages/browser-common/dist/feature-flags.js 61.7 kB
packages/browser-common/dist/feature-flags.mjs 55.4 kB
packages/browser-common/dist/index.js 5.87 kB
packages/browser-common/dist/index.mjs 447 B
packages/browser-common/dist/logs-config.js 3.35 kB
packages/browser-common/dist/logs-config.mjs 1.99 kB
packages/browser-common/dist/logs-types.js 1.46 kB
packages/browser-common/dist/logs-types.mjs 133 B
packages/browser-common/dist/logs.js 20 kB
packages/browser-common/dist/logs.mjs 18.1 kB
packages/browser-common/dist/persistence.js 585 B
packages/browser-common/dist/persistence.mjs 12 B
packages/browser-common/dist/pubsub.js 2.63 kB
packages/browser-common/dist/pubsub.mjs 1.35 kB
packages/browser-common/dist/rageclick.js 2.51 kB
packages/browser-common/dist/rageclick.mjs 1.21 kB
packages/browser-common/dist/survey-action-matcher.js 7.81 kB
packages/browser-common/dist/survey-action-matcher.mjs 5.96 kB
packages/browser-common/dist/survey-constants.js 4.61 kB
packages/browser-common/dist/survey-constants.mjs 2.17 kB
packages/browser-common/dist/survey-event-********.js 5.84 kB
packages/browser-common/dist/survey-event-********.mjs 3.7 kB
packages/browser-common/dist/survey-event-host.js 585 B
packages/browser-common/dist/survey-event-host.mjs 12 B
packages/browser-common/dist/survey-event-receiver-base.js 15.2 kB
packages/browser-common/dist/survey-event-receiver-base.mjs 13.5 kB
packages/browser-common/dist/survey-render-context.js 1.59 kB
packages/browser-common/dist/survey-render-context.mjs 285 B
packages/browser-common/dist/surveys-********.js 71.1 kB
packages/browser-common/dist/surveys-********.mjs 60.7 kB
packages/browser-common/dist/surveys-config.js 2.82 kB
packages/browser-common/dist/surveys-config.mjs 619 B
packages/browser-common/dist/surveys.js 28 kB
packages/browser-common/dist/surveys.mjs 23 kB
packages/browser-common/dist/surveys/components/BottomSection.js 3.4 kB
packages/browser-common/dist/surveys/components/BottomSection.mjs 1.74 kB
packages/browser-common/dist/surveys/components/ConfirmationMessage.js 4 kB
packages/browser-common/dist/surveys/components/ConfirmationMessage.mjs 2.09 kB
packages/browser-common/dist/surveys/components/IntroScreen.js 3.48 kB
packages/browser-common/dist/surveys/components/IntroScreen.mjs 1.68 kB
packages/browser-common/dist/surveys/components/PostHogLogo.js 2 kB
packages/browser-common/dist/surveys/components/PostHogLogo.mjs 614 B
packages/browser-common/dist/surveys/components/QuestionHeader.js 3.48 kB
packages/browser-common/dist/surveys/components/QuestionHeader.mjs 1.64 kB
packages/browser-common/dist/surveys/components/QuestionTypes.js 25.9 kB
packages/browser-common/dist/surveys/components/QuestionTypes.mjs 21 kB
packages/browser-common/dist/surveys/icons.js 15.5 kB
packages/browser-common/dist/surveys/icons.mjs 12.3 kB
packages/browser-common/dist/surveys/survey-branching.js 5.99 kB
packages/browser-common/dist/surveys/survey-branching.mjs 3.9 kB
packages/browser-common/dist/surveys/survey-styles.js 14.7 kB
packages/browser-common/dist/surveys/survey-styles.mjs 13.4 kB
packages/browser-common/dist/surveys/survey-translations.js 2.69 kB
packages/browser-common/dist/surveys/survey-translations.mjs 1.08 kB
packages/browser-common/dist/surveys/survey-url-prefill.js 7.99 kB
packages/browser-common/dist/surveys/survey-url-prefill.mjs 5.62 kB
packages/browser-common/dist/surveys/surveys-extension-utils.js 33.9 kB
packages/browser-common/dist/surveys/surveys-extension-utils.mjs 25.7 kB
packages/browser-common/dist/token.js 585 B
packages/browser-common/dist/token.mjs 12 B
packages/browser-common/dist/types/compression.js 1.37 kB
packages/browser-common/dist/types/compression.mjs 93 B
packages/browser-common/dist/types/feature-flags.js 585 B
packages/browser-common/dist/types/feature-flags.mjs 12 B
packages/browser-common/dist/types/index.js 4.16 kB
packages/browser-common/dist/types/index.mjs 181 B
packages/browser-common/dist/types/network-recording.js 585 B
packages/browser-common/dist/types/network-recording.mjs 12 B
packages/browser-common/dist/types/remote-config.js 585 B
packages/browser-common/dist/types/remote-config.mjs 12 B
packages/browser-common/dist/types/surveys.js 585 B
packages/browser-common/dist/types/surveys.mjs 12 B
packages/browser-common/dist/utils/array-at-********.js 619 B
packages/browser-common/dist/utils/array-at-********.mjs 437 B
packages/browser-common/dist/utils/array-find-last-********.js 604 B
packages/browser-common/dist/utils/array-find-last-********.mjs 422 B
packages/browser-common/dist/utils/autocapture-utils.js 26.4 kB
packages/browser-common/dist/utils/autocapture-utils.mjs 20.3 kB
packages/browser-common/dist/utils/blocked-uas.js 2.2 kB
packages/browser-common/dist/utils/blocked-uas.mjs 598 B
packages/browser-common/dist/utils/console-********.js 1.49 kB
packages/browser-common/dist/utils/console-********.mjs 171 B
packages/browser-common/dist/utils/convert-to-url.js 1.62 kB
packages/browser-common/dist/utils/convert-to-url.mjs 298 B
packages/browser-common/dist/utils/cookie-utils.js 1.99 kB
packages/browser-common/dist/utils/cookie-utils.mjs 673 B
packages/browser-common/dist/utils/device-model-utils.js 2.08 kB
packages/browser-common/dist/utils/device-model-utils.mjs 678 B
packages/browser-common/dist/utils/element-utils.js 2.56 kB
packages/browser-common/dist/utils/element-utils.mjs 804 B
packages/browser-common/dist/utils/elements-chain-utils.js 2.86 kB
packages/browser-common/dist/utils/elements-chain-utils.mjs 1.23 kB
packages/browser-common/dist/utils/encode-utils.js 1.49 kB
packages/browser-common/dist/utils/encode-utils.mjs 205 B
packages/browser-common/dist/utils/event-utils.js 16 kB
packages/browser-common/dist/utils/event-utils.mjs 10.1 kB
packages/browser-common/dist/utils/general-utils.js 7.83 kB
packages/browser-common/dist/utils/general-utils.mjs 4.77 kB
packages/browser-common/dist/utils/globals.js 2.83 kB
packages/browser-common/dist/utils/globals.mjs 842 B
packages/browser-common/dist/utils/logger.js 3.41 kB
packages/browser-common/dist/utils/logger.mjs 1.62 kB
packages/browser-common/dist/utils/matcher-utils.js 2.78 kB
packages/browser-common/dist/utils/matcher-utils.mjs 1.3 kB
packages/browser-common/dist/utils/patch.js 2.94 kB
packages/browser-common/dist/utils/patch.mjs 1.62 kB
packages/browser-common/dist/utils/promise-utils.js 1.45 kB
packages/browser-common/dist/utils/promise-utils.mjs 169 B
packages/browser-common/dist/utils/property-utils.js 3.63 kB
packages/browser-common/dist/utils/property-utils.mjs 1.6 kB
packages/browser-common/dist/utils/prototype-utils.js 3.61 kB
packages/browser-common/dist/utils/prototype-utils.mjs 1.86 kB
packages/browser-common/dist/utils/regex-utils.js 1.55 kB
packages/browser-common/dist/utils/regex-utils.mjs 71 B
packages/browser-common/dist/utils/request-reachability.js 2.55 kB
packages/browser-common/dist/utils/request-reachability.mjs 996 B
packages/browser-common/dist/utils/request-utils.js 6.42 kB
packages/browser-common/dist/utils/request-utils.mjs 3.57 kB
packages/browser-common/dist/utils/sanitize-url.js 1.76 kB
packages/browser-common/dist/utils/sanitize-url.mjs 475 B
packages/browser-common/dist/utils/simple-event-emitter.js 1.86 kB
packages/browser-common/dist/utils/simple-event-emitter.mjs 553 B
packages/browser-common/dist/utils/stylesheet-loader.js 2.23 kB
packages/browser-common/dist/utils/stylesheet-loader.mjs 823 B
packages/browser-common/dist/utils/survey-utils.js 5.72 kB
packages/browser-common/dist/utils/survey-utils.mjs 2.04 kB
packages/browser-common/dist/utils/timezone.js 1.44 kB
packages/browser-common/dist/utils/timezone.mjs 163 B
packages/browser-common/dist/utils/type-utils.js 1.68 kB
packages/browser-common/dist/utils/type-utils.mjs 258 B
packages/browser-common/dist/utils/url-targeting-utils.js 2.4 kB
packages/browser-common/dist/utils/url-targeting-utils.mjs 823 B
packages/browser-common/dist/utils/uuidv7.js 6.81 kB
packages/browser-common/dist/utils/uuidv7.mjs 5.26 kB
packages/browser-next/dist/analytics-buffer.js 7.69 kB
packages/browser-next/dist/analytics-buffer.mjs 6.03 kB
packages/browser-next/dist/analytics-options.js 585 B
packages/browser-next/dist/analytics-options.mjs 12 B
packages/browser-next/dist/analytics.js 1.67 kB
packages/browser-next/dist/analytics.mjs 259 B
packages/browser-next/dist/autocapture-options.js 1.85 kB
packages/browser-next/dist/autocapture-options.mjs 513 B
packages/browser-next/dist/autocapture.js 4.44 kB
packages/browser-next/dist/autocapture.mjs 3.01 kB
packages/browser-next/dist/automatic-analytics.js 1.64 kB
packages/browser-next/dist/automatic-analytics.mjs 298 B
packages/browser-next/dist/automatic-surveys.js 1.54 kB
packages/browser-next/dist/automatic-surveys.mjs 189 B
packages/browser-next/dist/bot-filter.js 2.38 kB
packages/browser-next/dist/bot-filter.mjs 1.09 kB
packages/browser-next/dist/browser-client.js 585 B
packages/browser-next/dist/browser-client.mjs 12 B
packages/browser-next/dist/capture-summary.js 2.14 kB
packages/browser-next/dist/capture-summary.mjs 647 B
packages/browser-next/dist/capture-v1.js 29.9 kB
packages/browser-next/dist/capture-v1.mjs 27.2 kB
packages/browser-next/dist/core.js 1.96 kB
packages/browser-next/dist/core.mjs 244 B
packages/browser-next/dist/event-buffer.js 5.32 kB
packages/browser-next/dist/event-buffer.mjs 4.04 kB
packages/browser-next/dist/extensions/registry.js 4.42 kB
packages/browser-next/dist/extensions/registry.mjs 3.12 kB
packages/browser-next/dist/flags-********.js 585 B
packages/browser-next/dist/flags-********.mjs 12 B
packages/browser-next/dist/flags-options.js 585 B
packages/browser-next/dist/flags-options.mjs 12 B
packages/browser-next/dist/flags-token.js 1.4 kB
packages/browser-next/dist/flags-token.mjs 80 B
packages/browser-next/dist/flags.js 6.52 kB
packages/browser-next/dist/flags.mjs 4.93 kB
packages/browser-next/dist/id.js 2.25 kB
packages/browser-next/dist/id.mjs 983 B
packages/browser-next/dist/index.js 5.46 kB
packages/browser-next/dist/index.mjs 3.38 kB
packages/browser-next/dist/lane.js 15.1 kB
packages/browser-next/dist/lane.mjs 13.8 kB
packages/browser-next/dist/logger.js 2.08 kB
packages/browser-next/dist/logger.mjs 742 B
packages/browser-next/dist/logs-********.js 585 B
packages/browser-next/dist/logs-********.mjs 12 B
packages/browser-next/dist/logs-options.js 1.84 kB
packages/browser-next/dist/logs-options.mjs 529 B
packages/browser-next/dist/logs.js 5.33 kB
packages/browser-next/dist/logs.mjs 3.83 kB
packages/browser-next/dist/named-error.js 1.57 kB
packages/browser-next/dist/named-error.mjs 271 B
packages/browser-next/dist/posthog.js 34.5 kB
packages/browser-next/dist/posthog.mjs 32 kB
packages/browser-next/dist/rate-limiter.js 2.89 kB
packages/browser-next/dist/rate-limiter.mjs 1.58 kB
packages/browser-next/dist/remote-config.js 1.85 kB
packages/browser-next/dist/remote-config.mjs 483 B
packages/browser-next/dist/request.js 4.99 kB
packages/browser-next/dist/request.mjs 3.58 kB
packages/browser-next/dist/state.js 24.9 kB
packages/browser-next/dist/state.mjs 23.1 kB
packages/browser-next/dist/surveys-********.js 585 B
packages/browser-next/dist/surveys-********.mjs 12 B
packages/browser-next/dist/surveys-extension.js 11.3 kB
packages/browser-next/dist/surveys-extension.mjs 9.73 kB
packages/browser-next/dist/surveys-options.js 1.44 kB
packages/browser-next/dist/surveys-options.mjs 112 B
packages/browser-next/dist/surveys.js 1.92 kB
packages/browser-next/dist/surveys.mjs 348 B
packages/browser-next/dist/types.js 585 B
packages/browser-next/dist/types.mjs 12 B
packages/browser-next/dist/version.js 1.31 kB
packages/browser-next/dist/version.mjs 45 B
packages/browser/dist/all-external-dependencies.js 392 kB
packages/browser/dist/conversations.js 72.1 kB
packages/browser/dist/crisp-chat-integration.js 1.66 kB
packages/browser/dist/customizations.full.js 19.4 kB
packages/browser/dist/customizations.js 19.1 kB
packages/browser/dist/dead-clicks-autocapture.js 24.1 kB
packages/browser/dist/element-inference.js 5.28 kB
packages/browser/dist/exception-autocapture.js 17.9 kB
packages/browser/dist/extension-bundles.js 188 kB
packages/browser/dist/external-scripts-loader.js 3.28 kB
packages/browser/dist/intercom-integration.js 1.71 kB
packages/browser/dist/lazy-********.js 215 kB
packages/browser/dist/loader.js 6.35 kB
packages/browser/dist/logs.js 7.21 kB
packages/browser/dist/posthog-********.js 215 kB
packages/browser/dist/product-tours-preview.js 78 kB
packages/browser/dist/product-tours.js 122 kB
packages/browser/dist/recorder-v2.js 135 kB
packages/browser/dist/recorder.js 135 kB
packages/browser/dist/rrweb-plugin-console-record.js 7.94 kB
packages/browser/dist/rrweb-types.js 2.41 kB
packages/browser/dist/rrweb.js 328 kB
packages/browser/dist/surveys-preview.js 88.6 kB
packages/browser/dist/surveys.js 112 kB
packages/browser/dist/tracing-headers.js 4.71 kB
packages/browser/dist/web-vitals-soft-navs.js 11.1 kB
packages/browser/dist/web-vitals-with-attribution-soft-navs.js 27 kB
packages/browser/dist/web-vitals-with-attribution.js 27 kB
packages/browser/dist/web-vitals.js 11 kB
packages/browser/react/dist/esm/index.js 23.3 kB
packages/browser/react/dist/esm/slim/index.js 19.5 kB
packages/browser/react/dist/esm/surveys/index.js 4.22 kB
packages/browser/react/dist/umd/index.js 27.8 kB
packages/browser/react/dist/umd/slim/index.js 23.5 kB
packages/browser/react/dist/umd/surveys/index.js 6.33 kB
packages/convex/dist/client/feature-flags/crypto.js 76 B
packages/convex/dist/client/feature-flags/evaluator.js 16.2 kB
packages/convex/dist/client/feature-flags/index.js 196 B
packages/convex/dist/client/feature-flags/match-********.js 5.7 kB
packages/convex/dist/client/feature-flags/types.js 44 B
packages/convex/dist/client/index.js 14.8 kB
packages/convex/dist/component/_generated/api.js 712 B
packages/convex/dist/component/_generated/component.js 212 B
packages/convex/dist/component/_generated/dataModel.js 230 B
packages/convex/dist/component/_generated/server.js 3.74 kB
packages/convex/dist/component/convex.config.js 1.66 kB
packages/convex/dist/component/crons.js 969 B
packages/convex/dist/component/lib.js 24.9 kB
packages/convex/dist/component/schema.js 1.17 kB
packages/convex/dist/component/version.js 67 B
packages/core/dist/cookie.js 5.44 kB
packages/core/dist/cookie.mjs 3.12 kB
packages/core/dist/error-tracking/chunk-ids.js 3.44 kB
packages/core/dist/error-tracking/chunk-ids.mjs 2.11 kB
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.4 kB
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.58 kB
packages/core/dist/error-tracking/coercers/error-coercer.mjs 1.24 kB
packages/core/dist/error-tracking/coercers/error-event-coercer.js 2.45 kB
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 1.05 kB
packages/core/dist/error-tracking/coercers/event-coercer.js 1.92 kB
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B
packages/core/dist/error-tracking/coercers/index.js 5.82 kB
packages/core/dist/error-tracking/coercers/index.mjs 326 B
packages/core/dist/error-tracking/coercers/object-coercer.js 4.13 kB
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.53 kB
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.76 kB
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.69 kB
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 1.25 kB
packages/core/dist/error-tracking/coercers/string-coercer.js 2.11 kB
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B
packages/core/dist/error-tracking/coercers/utils.js 2.16 kB
packages/core/dist/error-tracking/coercers/utils.mjs 716 B
packages/core/dist/error-tracking/error-properties-builder.js 10.1 kB
packages/core/dist/error-tracking/error-properties-builder.mjs 8.58 kB
packages/core/dist/error-tracking/exception-steps.js 6.1 kB
packages/core/dist/error-tracking/exception-steps.mjs 3.83 kB
packages/core/dist/error-tracking/index.js 4.62 kB
packages/core/dist/error-tracking/index.mjs 222 B
packages/core/dist/error-tracking/parsers/base.js 2.43 kB
packages/core/dist/error-tracking/parsers/base.mjs 961 B
packages/core/dist/error-tracking/parsers/chrome.js 2.83 kB
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB
packages/core/dist/error-tracking/parsers/gecko.js 2.57 kB
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB
packages/core/dist/error-tracking/parsers/index.js 8.87 kB
packages/core/dist/error-tracking/parsers/index.mjs 6.03 kB
packages/core/dist/error-tracking/parsers/node.js 4.31 kB
packages/core/dist/error-tracking/parsers/node.mjs 2.95 kB
packages/core/dist/error-tracking/parsers/opera.js 2.35 kB
packages/core/dist/error-tracking/parsers/opera.mjs 746 B
packages/core/dist/error-tracking/parsers/safari.js 1.98 kB
packages/core/dist/error-tracking/parsers/safari.mjs 574 B
packages/core/dist/error-tracking/parsers/winjs.js 1.82 kB
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B
packages/core/dist/error-tracking/release.js 1.68 kB
packages/core/dist/error-tracking/release.mjs 366 B
packages/core/dist/error-tracking/types.js 1.42 kB
packages/core/dist/error-tracking/types.mjs 131 B
packages/core/dist/error-tracking/utils.js 1.9 kB
packages/core/dist/error-tracking/utils.mjs 604 B
packages/core/dist/eventemitter.js 1.88 kB
packages/core/dist/eventemitter.mjs 571 B
packages/core/dist/featureFlagLocalEvaluation.js 28.9 kB
packages/core/dist/featureFlagLocalEvaluation.mjs 26.1 kB
packages/core/dist/featureFlagUtils.js 8.61 kB
packages/core/dist/featureFlagUtils.mjs 5.52 kB
packages/core/dist/gzip.js 5.88 kB
packages/core/dist/gzip.mjs 3.87 kB
packages/core/dist/index.js 27.9 kB
packages/core/dist/index.mjs 2.02 kB
packages/core/dist/logs/index.js 11.8 kB
packages/core/dist/logs/index.mjs 9.83 kB
packages/core/dist/logs/logs-utils.js 6.7 kB
packages/core/dist/logs/logs-utils.mjs 4.54 kB
packages/core/dist/logs/types.js 585 B
packages/core/dist/logs/types.mjs 12 B
packages/core/dist/metrics/config.js 2.05 kB
packages/core/dist/metrics/config.mjs 735 B
packages/core/dist/metrics/index.js 17 kB
packages/core/dist/metrics/index.mjs 14.1 kB
packages/core/dist/metrics/metrics-utils.js 3.67 kB
packages/core/dist/metrics/metrics-utils.mjs 1.68 kB
packages/core/dist/metrics/types.js 585 B
packages/core/dist/metrics/types.mjs 12 B
packages/core/dist/posthog-core-stateless.js 49.3 kB
packages/core/dist/posthog-core-stateless.mjs 45.9 kB
packages/core/dist/posthog-core.js 49.6 kB
packages/core/dist/posthog-core.mjs 44 kB
packages/core/dist/privacy.js 15.6 kB
packages/core/dist/privacy.mjs 13.9 kB
packages/core/dist/surveys/activation.js 2.29 kB
packages/core/dist/surveys/activation.mjs 572 B
packages/core/dist/surveys/events.js 5.82 kB
packages/core/dist/surveys/events.mjs 3.14 kB
packages/core/dist/surveys/index.js 7.48 kB
packages/core/dist/surveys/index.mjs 921 B
packages/core/dist/surveys/keys.js 1.8 kB
packages/core/dist/surveys/keys.mjs 350 B
packages/core/dist/surveys/property-********.js 3.8 kB
packages/core/dist/surveys/property-********.mjs 2.15 kB
packages/core/dist/surveys/shuffling.js 2.53 kB
packages/core/dist/surveys/shuffling.mjs 1.07 kB
packages/core/dist/surveys/translations.js 9.18 kB
packages/core/dist/surveys/translations.mjs 6.83 kB
packages/core/dist/surveys/validation.js 3.15 kB
packages/core/dist/surveys/validation.mjs 1.51 kB
packages/core/dist/testing/index.js 2.76 kB
packages/core/dist/testing/index.mjs 79 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.35 kB
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.85 kB
packages/core/dist/testing/test-utils.js 2.9 kB
packages/core/dist/testing/test-utils.mjs 1.11 kB
packages/core/dist/traces/config.js 4.62 kB
packages/core/dist/traces/config.mjs 3.27 kB
packages/core/dist/traces/context.js 1.64 kB
packages/core/dist/traces/context.mjs 318 B
packages/core/dist/traces/ids.js 3.2 kB
packages/core/dist/traces/ids.mjs 1.52 kB
packages/core/dist/traces/index.js 26.7 kB
packages/core/dist/traces/index.mjs 24 kB
packages/core/dist/traces/otlp.js 6.33 kB
packages/core/dist/traces/otlp.mjs 4.14 kB
packages/core/dist/traces/sanitize.js 3.59 kB
packages/core/dist/traces/sanitize.mjs 1.88 kB
packages/core/dist/traces/span.js 20 kB
packages/core/dist/traces/span.mjs 16.7 kB
packages/core/dist/traces/traceparent.js 4.54 kB
packages/core/dist/traces/traceparent.mjs 2.54 kB
packages/core/dist/traces/types.js 585 B
packages/core/dist/traces/types.mjs 12 B
packages/core/dist/tracing-headers.js 3.48 kB
packages/core/dist/tracing-headers.mjs 2.08 kB
packages/core/dist/types.js 8.53 kB
packages/core/dist/types.mjs 5.37 kB
packages/core/dist/utils/backoff.js 2.36 kB
packages/core/dist/utils/backoff.mjs 611 B
packages/core/dist/utils/bot-detection.js 4.17 kB
packages/core/dist/utils/bot-detection.mjs 2.58 kB
packages/core/dist/utils/browser-utils.js 1.57 kB
packages/core/dist/utils/browser-utils.mjs 182 B
packages/core/dist/utils/bucketed-rate-limiter.js 4.32 kB
packages/core/dist/utils/bucketed-rate-limiter.mjs 2.22 kB
packages/core/dist/utils/flush-timer.js 2.06 kB
packages/core/dist/utils/flush-timer.mjs 725 B
packages/core/dist/utils/index.js 17.8 kB
packages/core/dist/utils/index.mjs 3.69 kB
packages/core/dist/utils/json-utils.js 7.44 kB
packages/core/dist/utils/json-utils.mjs 5.02 kB
packages/core/dist/utils/logger.js 2.68 kB
packages/core/dist/utils/logger.mjs 1.29 kB
packages/core/dist/utils/number-utils.js 3.42 kB
packages/core/dist/utils/number-utils.mjs 1.68 kB
packages/core/dist/utils/otlp-********.js 3.94 kB
packages/core/dist/utils/otlp-********.mjs 1.97 kB
packages/core/dist/utils/otlp-any-value.js 7.96 kB
packages/core/dist/utils/otlp-any-value.mjs 5.77 kB
packages/core/dist/utils/promise-queue.js 2.58 kB
packages/core/dist/utils/promise-queue.mjs 1.25 kB
packages/core/dist/utils/string-utils.js 3.83 kB
packages/core/dist/utils/string-utils.mjs 1.97 kB
packages/core/dist/utils/type-utils.js 7.52 kB
packages/core/dist/utils/type-utils.mjs 3.27 kB
packages/core/dist/utils/user-agent-utils.js 18.5 kB
packages/core/dist/utils/user-agent-utils.mjs 14.7 kB
packages/core/dist/utils/webview-app-utils.js 3.54 kB
packages/core/dist/utils/webview-app-utils.mjs 2.23 kB
packages/core/dist/vendor/uuidv7.js 8.36 kB
packages/core/dist/vendor/uuidv7.mjs 6.7 kB
packages/mcp/dist/extensions/analytics-parameters.js 6.63 kB
packages/mcp/dist/extensions/analytics-parameters.mjs 4.27 kB
packages/mcp/dist/extensions/capture.js 4.11 kB
packages/mcp/dist/extensions/capture.mjs 2.65 kB
packages/mcp/dist/extensions/client-********.js 6.33 kB
packages/mcp/dist/extensions/client-********.mjs 3.71 kB
packages/mcp/dist/extensions/compatibility.js 5.45 kB
packages/mcp/dist/extensions/compatibility.mjs 3.4 kB
packages/mcp/dist/extensions/constants.js 6.33 kB
packages/mcp/dist/extensions/constants.mjs 3.83 kB
packages/mcp/dist/extensions/context-parameters.js 2.85 kB
packages/mcp/dist/extensions/context-parameters.mjs 893 B
packages/mcp/dist/extensions/conversation-id.js 6.41 kB
packages/mcp/dist/extensions/conversation-id.mjs 3.58 kB
packages/mcp/dist/extensions/detect.js 3.87 kB
packages/mcp/dist/extensions/detect.mjs 1.49 kB
packages/mcp/dist/extensions/event-types.js 1.78 kB
packages/mcp/dist/extensions/event-types.mjs 458 B
packages/mcp/dist/extensions/exceptions.js 2.67 kB
packages/mcp/dist/extensions/exceptions.mjs 1.19 kB
packages/mcp/dist/extensions/feedback.js 12.4 kB
packages/mcp/dist/extensions/feedback.mjs 9.48 kB
packages/mcp/dist/extensions/headers.js 2.08 kB
packages/mcp/dist/extensions/headers.mjs 643 B
packages/mcp/dist/extensions/ids.js 2.11 kB
packages/mcp/dist/extensions/ids.mjs 637 B
packages/mcp/dist/extensions/instrument-********.js 7.98 kB
packages/mcp/dist/extensions/instrument-********.mjs 5.43 kB
packages/mcp/dist/extensions/instrument-highlevel.js 15 kB
packages/mcp/dist/extensions/instrument-highlevel.mjs 11.8 kB
packages/mcp/dist/extensions/instrumentation.js 36.5 kB
packages/mcp/dist/extensions/instrumentation.mjs 29.6 kB
packages/mcp/dist/extensions/intent.js 3.3 kB
packages/mcp/dist/extensions/intent.mjs 1.64 kB
packages/mcp/dist/extensions/internal.js 4.99 kB
packages/mcp/dist/extensions/internal.mjs 2.88 kB
packages/mcp/dist/extensions/lib-********.js 1.7 kB
packages/mcp/dist/extensions/lib-********.mjs 267 B
packages/mcp/dist/extensions/logger.js 1.81 kB
packages/mcp/dist/extensions/logger.mjs 380 B
packages/mcp/dist/extensions/mcp-********.js 3.96 kB
packages/mcp/dist/extensions/mcp-********.mjs 2.24 kB
packages/mcp/dist/extensions/mcp-sdk-compat.js 5.86 kB
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 3.5 kB
packages/mcp/dist/extensions/model-parameters.js 4.59 kB
packages/mcp/dist/extensions/model-parameters.mjs 2.32 kB
packages/mcp/dist/extensions/output-instructions.js 6.21 kB
packages/mcp/dist/extensions/output-instructions.mjs 3.91 kB
packages/mcp/dist/extensions/posthog-events.js 12.3 kB
packages/mcp/dist/extensions/posthog-events.mjs 8.35 kB
packages/mcp/dist/extensions/posthog-mcp.js 16.8 kB
packages/mcp/dist/extensions/posthog-mcp.mjs 13.5 kB
packages/mcp/dist/extensions/request-headers.js 2.27 kB
packages/mcp/dist/extensions/request-headers.mjs 963 B
packages/mcp/dist/extensions/sanitization.js 4.56 kB
packages/mcp/dist/extensions/sanitization.mjs 2.77 kB
packages/mcp/dist/extensions/server-build.js 1.94 kB
packages/mcp/dist/extensions/server-build.mjs 482 B
packages/mcp/dist/extensions/session-token.js 5.47 kB
packages/mcp/dist/extensions/session-token.mjs 3.6 kB
packages/mcp/dist/extensions/session.js 6.79 kB
packages/mcp/dist/extensions/session.mjs 4.16 kB
packages/mcp/dist/extensions/sink.js 4.47 kB
packages/mcp/dist/extensions/sink.mjs 2.67 kB
packages/mcp/dist/extensions/tool-input.js 4.82 kB
packages/mcp/dist/extensions/tool-input.mjs 3.27 kB
packages/mcp/dist/extensions/tools.js 3.61 kB
packages/mcp/dist/extensions/tools.mjs 1.63 kB
packages/mcp/dist/extensions/tracing-helpers.js 2.51 kB
packages/mcp/dist/extensions/tracing-helpers.mjs 772 B
packages/mcp/dist/extensions/transport-********.js 3 kB
packages/mcp/dist/extensions/transport-********.mjs 1.09 kB
packages/mcp/dist/extensions/truncation.js 11.9 kB
packages/mcp/dist/extensions/truncation.mjs 9.99 kB
packages/mcp/dist/index.js 10.2 kB
packages/mcp/dist/index.mjs 5.54 kB
packages/mcp/dist/types.js 585 B
packages/mcp/dist/types.mjs 12 B
packages/mcp/dist/version.js 1.31 kB
packages/mcp/dist/version.mjs 46 B
packages/next/dist/app/PostHogProvider.js 5.37 kB
packages/next/dist/client/ClientPostHogProvider.js 2.28 kB
packages/next/dist/client/hooks.js 172 B
packages/next/dist/client/PostHogPageView.js 4.23 kB
packages/next/dist/index.client.js 401 B
packages/next/dist/index.edge.js 570 B
packages/next/dist/index.js 554 B
packages/next/dist/index.react-server.js 420 B
packages/next/dist/middleware/postHogMiddleware.js 4.08 kB
packages/next/dist/otel.js 1.12 kB
packages/next/dist/otel.unsupported.js 181 B
packages/next/dist/pages.client.js 225 B
packages/next/dist/pages.edge.js 294 B
packages/next/dist/pages.js 347 B
packages/next/dist/pages/createPostHog.js 1.48 kB
packages/next/dist/pages/getServerSidePostHog.js 1.48 kB
packages/next/dist/pages/PostHogPageView.js 1.77 kB
packages/next/dist/pages/PostHogProvider.js 1.58 kB
packages/next/dist/server.edge.js 795 B
packages/next/dist/server/captureRequestError.js 5.26 kB
packages/next/dist/server/clientCache.edge.js 305 B
packages/next/dist/server/clientCache.js 1.53 kB
packages/next/dist/server/clientCache.node.js 828 B
packages/next/dist/server/createPostHog.js 1.44 kB
packages/next/dist/server/getPostHog.js 3.89 kB
packages/next/dist/server/onRequestError.js 1.39 kB
packages/next/dist/server/onRequestError.types.js 59 B
packages/next/dist/shared/browser.js 195 B
packages/next/dist/shared/config.js 2.23 kB
packages/next/dist/shared/constants.js 201 B
packages/next/dist/shared/cookie.js 540 B
packages/next/dist/shared/identity.js 2.56 kB
packages/next/dist/shared/tracing-headers.js 2.18 kB
packages/nextjs-config/dist/config.js 13.3 kB
packages/nextjs-config/dist/config.mjs 11.7 kB
packages/nextjs-config/dist/index.js 2.21 kB
packages/nextjs-config/dist/index.mjs 30 B
packages/nextjs-config/dist/strip-sourcemap-********.js 5.46 kB
packages/nextjs-config/dist/strip-sourcemap-********.mjs 3.37 kB
packages/nextjs-config/dist/utils.js 4.81 kB
packages/nextjs-config/dist/utils.mjs 2.33 kB
packages/node/dist/ai-capture/batching.js 2.71 kB
packages/node/dist/ai-capture/batching.mjs 1.21 kB
packages/node/dist/ai-capture/routing.js 1.96 kB
packages/node/dist/ai-capture/routing.mjs 264 B
packages/node/dist/capture-v1/config.js 1.59 kB
packages/node/dist/capture-v1/config.mjs 283 B
packages/node/dist/capture-v1/errors.js 1.99 kB
packages/node/dist/capture-v1/errors.mjs 694 B
packages/node/dist/capture-v1/routing.js 1.77 kB
packages/node/dist/capture-v1/routing.mjs 279 B
packages/node/dist/capture-v1/sender.js 11.5 kB
packages/node/dist/capture-v1/sender.mjs 9.94 kB
packages/node/dist/capture-v1/transform.js 5.22 kB
packages/node/dist/capture-v1/transform.mjs 3.65 kB
packages/node/dist/capture-v1/types.js 585 B
packages/node/dist/capture-v1/types.mjs 12 B
packages/node/dist/entrypoints/index.edge.js 3.66 kB
packages/node/dist/entrypoints/index.edge.mjs 720 B
packages/node/dist/entrypoints/index.node.js 6.45 kB
packages/node/dist/entrypoints/index.node.mjs 1.77 kB
packages/node/dist/entrypoints/nestjs.js 2.27 kB
packages/node/dist/entrypoints/nestjs.mjs 42 B
packages/node/dist/entrypoints/otel.js 3.93 kB
packages/node/dist/entrypoints/otel.mjs 2.35 kB
packages/node/dist/experimental.js 852 B
packages/node/dist/experimental.mjs 279 B
packages/node/dist/extensions/context/context.js 2.62 kB
packages/node/dist/extensions/context/context.mjs 1.14 kB
packages/node/dist/extensions/context/event-context.js 1.93 kB
packages/node/dist/extensions/context/event-context.mjs 501 B
packages/node/dist/extensions/context/lifetime.js 2.01 kB
packages/node/dist/extensions/context/lifetime.mjs 571 B
packages/node/dist/extensions/context/listeners.js 2.35 kB
packages/node/dist/extensions/context/listeners.mjs 788 B
packages/node/dist/extensions/context/span-context.node.js 1.8 kB
packages/node/dist/extensions/context/span-context.node.mjs 355 B
packages/node/dist/extensions/context/types.js 585 B
packages/node/dist/extensions/context/types.mjs 12 B
packages/node/dist/extensions/error-tracking/autocapture.js 5.29 kB
packages/node/dist/extensions/error-tracking/autocapture.mjs 3.62 kB
packages/node/dist/extensions/error-tracking/index.js 4.74 kB
packages/node/dist/extensions/error-tracking/index.mjs 3.38 kB
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 11.7 kB
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 9.64 kB
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.87 kB
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.js 2.07 kB
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs 624 B
packages/node/dist/extensions/error-tracking/trace-context.js 2.25 kB
packages/node/dist/extensions/error-tracking/trace-context.mjs 913 B
packages/node/dist/extensions/express.js 6.42 kB
packages/node/dist/extensions/express.mjs 4.07 kB
packages/node/dist/extensions/feature-flags/cache.js 585 B
packages/node/dist/extensions/feature-flags/cache.mjs 12 B
packages/node/dist/extensions/feature-flags/crypto.js 1.37 kB
packages/node/dist/extensions/feature-flags/crypto.mjs 42 B
packages/node/dist/extensions/feature-flags/feature-flags.js 43.7 kB
packages/node/dist/extensions/feature-flags/feature-flags.mjs 41 kB
packages/node/dist/extensions/nestjs.js 5.97 kB
packages/node/dist/extensions/nestjs.mjs 3.62 kB
packages/node/dist/extensions/sentry-integration.js 4.99 kB
packages/node/dist/extensions/sentry-integration.mjs 3.37 kB
packages/node/dist/extensions/tracing-headers.js 6.85 kB
packages/node/dist/extensions/tracing-headers.mjs 4.61 kB
packages/node/dist/extensions/url-utils.js 2.32 kB
packages/node/dist/extensions/url-utils.mjs 785 B
packages/node/dist/feature-flag-evaluations.js 6.72 kB
packages/node/dist/feature-flag-evaluations.mjs 5.24 kB
packages/node/dist/gzip.node.js 1.83 kB
packages/node/dist/gzip.node.mjs 416 B
packages/node/dist/host-os.node.js 1.8 kB
packages/node/dist/host-os.node.mjs 349 B
packages/node/dist/storage-memory.js 1.61 kB
packages/node/dist/storage-memory.mjs 297 B
packages/node/dist/types.js 1.59 kB
packages/node/dist/types.mjs 292 B
packages/node/dist/version.js 1.31 kB
packages/node/dist/version.mjs 46 B
packages/nuxt/dist/module.mjs 8.05 kB
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 690 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B
packages/nuxt/dist/runtime/nitro-plugin-v2.js 817 B
packages/nuxt/dist/runtime/nitro-plugin-v3.js 893 B
packages/nuxt/dist/runtime/nitro-plugin.js 3.14 kB
packages/nuxt/dist/runtime/server-client.js 32 B
packages/nuxt/dist/runtime/server.js 127 B
packages/nuxt/dist/runtime/vue-plugin.js 1.13 kB
packages/openfeature-node-provider/dist/index.js 1.86 kB
packages/openfeature-node-provider/dist/index.mjs 122 B
packages/openfeature-node-provider/dist/mapping.js 5.66 kB
packages/openfeature-node-provider/dist/mapping.mjs 3.5 kB
packages/openfeature-node-provider/dist/provider.js 4.08 kB
packages/openfeature-node-provider/dist/provider.mjs 2.59 kB
packages/openfeature-web-provider/dist/index.js 1.84 kB
packages/openfeature-web-provider/dist/index.mjs 119 B
packages/openfeature-web-provider/dist/mapping.js 5.38 kB
packages/openfeature-web-provider/dist/mapping.mjs 3.18 kB
packages/openfeature-web-provider/dist/provider.js 4.51 kB
packages/openfeature-web-provider/dist/provider.mjs 3.06 kB
packages/plugin-utils/dist/chunk-ids.js 3.96 kB
packages/plugin-utils/dist/chunk-ids.mjs 2.11 kB
packages/plugin-utils/dist/cli.js 4.47 kB
packages/plugin-utils/dist/cli.mjs 2.72 kB
packages/plugin-utils/dist/config.js 3.6 kB
packages/plugin-utils/dist/config.mjs 2.25 kB
packages/plugin-utils/dist/index.js 4.5 kB
packages/plugin-utils/dist/index.mjs 197 B
packages/plugin-utils/dist/spawn-local.js 3.17 kB
packages/plugin-utils/dist/spawn-local.mjs 1.66 kB
packages/plugin-utils/dist/utils.js 3.36 kB
packages/plugin-utils/dist/utils.mjs 1.3 kB
packages/react-native/dist/autocapture.js 8.42 kB
packages/react-native/dist/error-tracking/exception-context.js 2.25 kB
packages/react-native/dist/error-tracking/fatal-payload.js 6.61 kB
packages/react-native/dist/error-tracking/index.js 17.2 kB
packages/react-native/dist/error-tracking/utils.js 6.03 kB
packages/react-native/dist/frameworks/wix-navigation.js 1.35 kB
packages/react-native/dist/hooks/useFeatureFlag.js 1.9 kB
packages/react-native/dist/hooks/useFeatureFlagResult.js 1.03 kB
packages/react-native/dist/hooks/useFeatureFlags.js 985 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.31 kB
packages/react-native/dist/hooks/usePostHog.js 583 B
packages/react-native/dist/hooks/utils.js 1.02 kB
packages/react-native/dist/index.js 4.36 kB
packages/react-native/dist/logs-********.js 3.71 kB
packages/react-native/dist/native-deps.js 9.57 kB
packages/react-native/dist/optional/OptionalAsyncStorage.js 348 B
packages/react-native/dist/optional/OptionalExpoApplication.js 429 B
packages/react-native/dist/optional/OptionalExpoDevice.js 394 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 437 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 480 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 436 B
packages/react-native/dist/optional/OptionalExpoUpdates.js 382 B
packages/react-native/dist/optional/OptionalPlugin.js 1.36 kB
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 473 B
packages/react-native/dist/optional/OptionalReactNativeExceptionsManager.js 626 B
packages/react-native/dist/optional/OptionalReactNativeExceptionsManager.web.js 287 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 359 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 473 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 504 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 700 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 923 B
packages/react-native/dist/posthog-rn.js 97.6 kB
packages/react-native/dist/PostHogContext.js 372 B
packages/react-native/dist/PostHogErrorBoundary.js 3.98 kB
packages/react-native/dist/PostHogMaskView.js 1.72 kB
packages/react-native/dist/PostHogProvider.js 6.15 kB
packages/react-native/dist/storage.js 6.85 kB
packages/react-native/dist/surveys/components/BottomSection.js 1.69 kB
packages/react-native/dist/surveys/components/Cancel.js 1.19 kB
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.99 kB
packages/react-native/dist/surveys/components/IntroMessage.js 1.87 kB
packages/react-native/dist/surveys/components/QuestionHeader.js 1.69 kB
packages/react-native/dist/surveys/components/QuestionTypes.js 16.1 kB
packages/react-native/dist/surveys/components/SurveyModal.js 7.95 kB
packages/react-native/dist/surveys/components/Surveys.js 8.7 kB
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 3.42 kB
packages/react-native/dist/surveys/icons.js 10.1 kB
packages/react-native/dist/surveys/index.js 634 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 10.4 kB
packages/react-native/dist/surveys/safeStyleSheet.js 491 B
packages/react-native/dist/surveys/survey-********.js 7.8 kB
packages/react-native/dist/surveys/survey-shuffling.js 2.38 kB
packages/react-native/dist/surveys/survey-translations.js 1.22 kB
packages/react-native/dist/surveys/surveys-utils.js 12 kB
packages/react-native/dist/surveys/useActivatedSurveys.js 3.89 kB
packages/react-native/dist/surveys/useSurveyStorage.js 3.07 kB
packages/react-native/dist/tooling/expoconfig.js 42.3 kB
packages/react-native/dist/tooling/metroconfig.js 2.36 kB
packages/react-native/dist/tooling/posthogMetroSerializer.js 7.5 kB
packages/react-native/dist/tooling/utils.js 4.49 kB
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 109 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 276 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.61 kB
packages/react-native/dist/types.js 104 B
packages/react-native/dist/utils.js 1.83 kB
packages/react-native/dist/version.js 166 B
packages/react/dist/esm/index.js 23.3 kB
packages/react/dist/esm/slim/index.js 19.5 kB
packages/react/dist/esm/surveys/index.js 4.22 kB
packages/react/dist/umd/index.js 27.8 kB
packages/react/dist/umd/slim/index.js 23.5 kB
packages/react/dist/umd/surveys/index.js 6.33 kB
packages/rollup-plugin/dist/index.js 14.6 kB
packages/rrweb/all/dist/rrweb-all.cjs 660 kB
packages/rrweb/all/dist/rrweb-all.js 659 kB
packages/rrweb/all/dist/rrweb-all.umd.cjs 689 kB
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 340 kB
packages/rrweb/packer/dist/browser-********.cjs 17.9 kB
packages/rrweb/packer/dist/browser-********.js 17.5 kB
packages/rrweb/packer/dist/pack.cjs 401 B
packages/rrweb/packer/dist/pack.js 301 B
packages/rrweb/packer/dist/pack.umd.cjs 1.67 kB
packages/rrweb/packer/dist/pack.umd.min.cjs 1.11 kB
packages/rrweb/packer/dist/packer.cjs 276 B
packages/rrweb/packer/dist/packer.js 133 B
packages/rrweb/packer/dist/packer.umd.cjs 694 B
packages/rrweb/packer/dist/packer.umd.min.cjs 626 B
packages/rrweb/packer/dist/unpack.cjs 737 B
packages/rrweb/packer/dist/unpack.js 637 B
packages/rrweb/packer/dist/unpack.umd.cjs 1.14 kB
packages/rrweb/packer/dist/unpack.umd.min.cjs 953 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.cjs 34.9 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.js 34.8 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.cjs 37 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.min.cjs 22.9 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.cjs 31.8 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.js 31.7 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.cjs 33.7 kB
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.min.cjs 21.1 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.cjs 17.5 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 17.4 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 16.8 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 8.91 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 7.05 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 6.95 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 7.34 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 3.91 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.cjs 663 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.js 540 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.cjs 1.1 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.min.cjs 827 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.cjs 816 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.js 715 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.cjs 1.25 kB
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.min.cjs 966 B
packages/rrweb/record/dist/rrweb-record.cjs 226 kB
packages/rrweb/record/dist/rrweb-record.js 226 kB
packages/rrweb/record/dist/rrweb-record.umd.cjs 230 kB
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 112 kB
packages/rrweb/replay/dist/rrweb-replay.cjs 439 kB
packages/rrweb/replay/dist/rrweb-replay.js 439 kB
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 461 kB
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 229 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 143 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 142 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 156 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 76.8 kB
packages/rrweb/rrdom/dist/rrdom.cjs 168 kB
packages/rrweb/rrdom/dist/rrdom.js 168 kB
packages/rrweb/rrdom/dist/rrdom.umd.cjs 179 kB
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 87.3 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-********.cjs 133 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-********.js 132 kB
packages/rrweb/rrweb-snapshot/dist/record.cjs 4.33 kB
packages/rrweb/rrweb-snapshot/dist/record.js 3.04 kB
packages/rrweb/rrweb-snapshot/dist/record.umd.cjs 95.3 kB
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 44.9 kB
packages/rrweb/rrweb-snapshot/dist/replay.cjs 1.96 kB
packages/rrweb/rrweb-snapshot/dist/replay.js 1.31 kB
packages/rrweb/rrweb-snapshot/dist/replay.umd.cjs 207 kB
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 91.2 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-********.cjs 4.62 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-********.js 3.22 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.cjs 250 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.min.cjs 112 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-********.cjs 35.1 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-********.js 33.2 kB
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 50.6 kB
packages/rrweb/rrweb-snapshot/dist/types-********.js 45.3 kB
packages/rrweb/rrweb/dist/rrweb.cjs 645 kB
packages/rrweb/rrweb/dist/rrweb.js 644 kB
packages/rrweb/rrweb/dist/rrweb.umd.cjs 671 kB
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 331 kB
packages/rrweb/types/dist/rrweb-types.cjs 5.8 kB
packages/rrweb/types/dist/rrweb-types.js 5.5 kB
packages/rrweb/types/dist/rrweb-types.umd.cjs 6.06 kB
packages/rrweb/types/dist/rrweb-types.umd.min.cjs 2.95 kB
packages/rrweb/utils/dist/rrweb-utils.cjs 10.9 kB
packages/rrweb/utils/dist/rrweb-utils.js 10.4 kB
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 11 kB
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 5.41 kB
packages/types/dist/capture-log.js 585 B
packages/types/dist/capture-log.mjs 12 B
packages/types/dist/capture-metric.js 1.47 kB
packages/types/dist/capture-metric.mjs 93 B
packages/types/dist/capture.js 585 B
packages/types/dist/capture.mjs 12 B
packages/types/dist/common.js 585 B
packages/types/dist/common.mjs 12 B
packages/types/dist/feature-flags.js 585 B
packages/types/dist/feature-flags.mjs 12 B
packages/types/dist/index.js 1.83 kB
packages/types/dist/index.mjs 137 B
packages/types/dist/posthog-config.js 1.53 kB
packages/types/dist/posthog-config.mjs 209 B
packages/types/dist/posthog.js 585 B
packages/types/dist/posthog.mjs 12 B
packages/types/dist/request.js 585 B
packages/types/dist/request.mjs 12 B
packages/types/dist/segment.js 585 B
packages/types/dist/segment.mjs 12 B
packages/types/dist/session-recording.js 585 B
packages/types/dist/session-recording.mjs 12 B
packages/types/dist/survey.js 585 B
packages/types/dist/survey.mjs 12 B
packages/types/dist/toolbar.js 585 B
packages/types/dist/toolbar.mjs 12 B
packages/types/dist/traces.js 585 B
packages/types/dist/traces.mjs 12 B
packages/types/dist/tree-shakeable.js 585 B
packages/types/dist/tree-shakeable.mjs 12 B
packages/web/dist/index.cjs 9.09 kB
packages/web/dist/index.mjs 8.93 kB
packages/webpack-plugin/dist/config.js 3.55 kB
packages/webpack-plugin/dist/config.mjs 2.48 kB
packages/webpack-plugin/dist/index.js 20.2 kB
packages/webpack-plugin/dist/index.mjs 15.6 kB
tooling/changelog/dist/index.js 399 B
tooling/rollup-utils/dist/index.js 1.17 kB
tooling/sdk-mock-server/dist/decode.js 2.03 kB
tooling/sdk-mock-server/dist/index.js 16 kB
tooling/sdk-mock-server/dist/state.js 3.79 kB

compressed-size-action

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

posthog-js Compliance Report

Date: 2026-10-29 12:32:28 UTC
Duration: 88935ms

✅ All Tests Passed!

26/26 tests passed


Capture Tests

✅ 26/26 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields Client ✅ 165ms
Format Validation.Event Has Uuid ✅ 20ms
Format Validation.Event Has Lib Properties ✅ 15ms
Format Validation.Distinct Id Is String Client ✅ 17ms
Format Validation.Token Is Present Client ✅ 18ms
Format Validation.Custom Properties Preserved ✅ 16ms
Format Validation.Event Has Timestamp ✅ 15ms
Retry Behavior.Retries On 503 ✅ 5018ms
Retry Behavior.Does Not Retry On 400 ✅ 2019ms
Retry Behavior.Does Not Retry On 401 ✅ 2017ms
Retry Behavior.Respects Retry After Header ✅ 5018ms
Retry Behavior.Implements Backoff ✅ 15024ms
Retry Behavior.Retries On 500 ✅ 5018ms
Retry Behavior.Retries On 502 ✅ 5018ms
Retry Behavior.Retries On 504 ✅ 5016ms
Retry Behavior.Max Retries Respected ✅ 15026ms
Deduplication.Generates Unique Uuids ✅ 49ms
Deduplication.Preserves Uuid On Retry ✅ 5016ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10022ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5022ms
Deduplication.No Duplicate Events In Batch ✅ 21ms
Deduplication.Different Events Have Different Uuids ✅ 13ms
Batch Format.Flush With No Events Sends Nothing ✅ 6ms
Error Handling.Does Not Retry On 403 ✅ 2013ms
Error Handling.Does Not Retry On 413 ✅ 2015ms
Error Handling.Retries On 408 ✅ 5018ms

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed 1b7a0cd: 3 Should fix.

Comment thread packages/node/src/emails/errors.ts Outdated
Comment on lines +80 to +81
case 422:
return 'invalid_idempotent_request'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Distinguish validation failures from idempotency errors on HTTP 422

For suppressed recipients or paused sending, the current template endpoint returns HTTP 422 with recipient_suppressed, sending_paused, or sending_suspended. emailErrorName labels all these as invalid_idempotent_request, so callers branching on the promised Resend-style names handle them incorrectly. Reserve that name for idempotency_key_reused and classify the other codes as validation errors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9eb1ef. On a 422, only idempotency_key_reused is now invalid_idempotent_request. recipient_suppressed, sending_paused and sending_suspended are validation_error, as PostHog/posthog#120921 names them. The name table test has a new 422 recipient_suppressed row. posthog-python gets the same change in PostHog/posthog-python@d2d4511.

Comment thread packages/node/src/emails/emails.ts Outdated
Comment on lines +166 to +171
const response = await Promise.race([
Promise.resolve().then(() =>
this.hooks.fetch(url, { method: 'POST', headers, body, signal: controller.signal })
),
deadline,
])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Cancel response bodies that arrive after the request deadline

When an injected fetch ignores abort and resolves after the deadline, request() has already exited and discards the late response without consuming or cancelling its body. Repeated timeouts leave pooled connections occupied until upstream cleanup, exhausting transport resources. Attach late-response cancellation as the core transport already does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9eb1ef. When the deadline aborts the request, a response the injected fetch returns later has its body cancelled, as the core transport does. "times out a request that answers too late and releases the late response" covers this.

Comment thread packages/node/src/emails/emails.ts Outdated
throw invalid('invalid_max_retries', 'maxRetries must be a nonnegative integer.', 'maxRetries')
}

const payload: Record<string, unknown> = { to, message_data: templateData ?? {} }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Expose and forward the per-send engagement tracking control

For transactional emails that require tracking disabled, SendEmailOptions provides no captureEngagement option, and prepareSend drops it even when JavaScript callers pass false. The cross-SDK contract in PostHog/posthog#120921 requires this control on both forms; its absence prevents callers from disabling open and click capture. Add the option and serialize capture_engagement, defaulting to true.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not adding this yet. PostHog/posthog#120921 defines capture_engagement, but the template send endpoint this SDK calls (/messaging_templates/{id}/send/) does not accept it, so captureEngagement: false would be silently ignored and opens and clicks would still be captured. It can go in when the server supports it, which is planned for the single /messaging/send/email/ endpoint. posthog-python makes the same call.

…ponses

- The template send route answers 422 for recipient_suppressed, sending_paused and sending_suspended as well as idempotency_key_reused. Only idempotency_key_reused is now invalid_idempotent_request; the send checks are validation_error, as the cross-SDK contract names them.
- A response that an injected fetch returns after the deadline now has its body cancelled, as the core transport does, so repeated timeouts don't keep pooled connections busy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@mayteio
mayteio marked this pull request as ready for review October 26, 2026 16:14
@mayteio
mayteio requested a review from a team as a code owner October 26, 2026 16:14
A disabled client returned { data: { id: null }, error: null }, so a caller that treats a result without an error as sent dropped the email silently. It now sends nothing and returns the error client_disabled (name application_error), as the cross-SDK contract in PostHog/posthog#120921 defines. SendEmailResult.id is always the queued message ID, so its type is string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

mayteio commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

@PostHog review --deep

@mayteio mayteio added the posthog-review label Oct 27, 2026 — with PostHog

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed b551aa4: 3 Should fix.

This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.

This Standard review started from the posthog-review label. Comment @posthog review --deep for a Deep review, or @posthog help to see all commands.

Comment thread packages/node/src/emails/emails.ts Outdated
Comment on lines +180 to +183
const text = await Promise.race([response.text(), deadline])
return { status: response.status, payload: parseJson(text), retryAfterMs: readRetryAfter(response) }
} finally {
clearTimeout(timer!)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Cancel received response bodies when body reads time out

When an injected fetch returns headers before the deadline but its text() ignores abort and stalls, request() times out without cancelling the received body. The late-response callback has already run, so repeated retries leave connections occupied. Retain the response outside try and cancel its body on timeout in finally, as the core transport does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9cb1bf. request() now keeps the response outside the try and, when the deadline fires during the body read, cancels response.body without awaiting it. The new test "times out a response body that stalls and cancels it" covers a fetch whose text() never settles.

Comment thread packages/node/src/emails/emails.ts Outdated
Comment on lines +74 to +79
const prepared = prepareSend(options, this.config.maxRetries)
if (this.hooks.isDisabled()) {
throw new EmailError({
code: 'client_disabled',
message: 'The PostHog client is disabled, so no email was sent.',
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Reject email sends after client shutdown

After await posthog.shutdown(), a valid emails.send() still queues an email because send() checks only isDisabled(), and shutdown never sets that flag. This violates the shared email contract's client_closed behavior and permits email delivery after teardown. Track the client's closed state and return client_closed before issuing requests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9cb1bf. The client now records shutdown at the start of _shutdown() and passes an isClosed hook to EmailSender, so a send after shutdown() returns client_closed before any request. The new test "sends nothing after shutdown and returns client_closed" checks the code, the application_error name, and that fetch is not called.

Comment on lines +115 to +120
const headers: Record<string, string> = {
Authorization: `Bearer ${secretKey}`,
Accept: 'application/json',
'Content-Type': 'application/json',
'Idempotency-Key': prepared.idempotencyKey,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Forward the contractual migration attribution header

For apps migrating from another email provider, the shared contract requires migratedFrom and an X-PostHog-Migrated-From header on every email request. PostHogOptions exposes no such option, and deliver() never forwards it, so these sends lose migration attribution. Add the client option and propagate its value into the request headers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining for now. No PostHog server code reads X-PostHog-Migrated-From yet, and posthog-python does not send it either, so adding migratedFrom would publish an option that does nothing. We can add it in both SDKs when the server reads it.

@posthog posthog Bot removed the posthog-review label Oct 27, 2026
…utdown

When an injected fetch answers before the deadline but its body read stalls, the email request now cancels the received body after the timeout, so it frees its connection.

After shutdown(), emails.send() now returns client_closed before any request, as the cross-SDK contract requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@mayteio mayteio added the posthog-review label Oct 27, 2026 — with PostHog

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed d9cb1bf: 2 Should fix.

This is review round 4 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.

This Standard review started from the posthog-review label. Comment @posthog review --deep for a Deep review, or @posthog help to see all commands.

maxRetries: nonNegativeIntegerOr(this.options.emailRequestMaxRetries, DEFAULT_EMAIL_REQUEST_MAX_RETRIES),
},
{
fetch: (url, fetchOptions) => this.fetch(url, fetchOptions),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Include active email sends in shutdown draining

When shutdown starts during an email request or retry backoff, it resolves without waiting because email sends bypass addPendingPromise and the queue that _shutdown() drains. A signal handler that exits after awaiting shutdown interrupts transactional sends despite an unexpired shutdown budget. Register each complete send promise, including retries, with the pending queue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3b21e02. EmailSender now tracks each send, retries included, and _shutdown() waits for them within the shutdown budget it already has. A send that starts after shutdown began still returns client_closed. I kept these sends out of addPendingPromise, because flush() (the automatic flush too) waits on that queue, so a send in its retry backoff would hold back event delivery. The new test "waits for a send in its retry backoff before shutdown resolves" covers a 503 followed by a retry.

Comment thread packages/node/src/emails/emails.ts Outdated
try {
const result = parseReply(await this.request(url, headers, prepared.body))
for (const warning of result.warnings) {
this.hooks.logger.warn(`PostHog email warning ${warning.code}: ${warning.message}`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Log email warnings outside debug mode

With debug mode off (the default), successful sends containing warnings never log them: deliver() calls the client's _logger.warn, whose logMsgIfDebug gate discards the message. Production logs therefore hide server guidance such as a superseded template while callers see a successful send. Route these warnings through an always-enabled warning hook.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining. posthog-node logs only in debug mode by design, and this SDK keeps that policy. Callers get every warning in data.warnings on the result, and the template send endpoint this SDK calls returns no warnings today.

@posthog posthog Bot removed the posthog-review label Oct 27, 2026
EmailSender now tracks each send, retries included, and shutdown() waits for those sends within its existing timeout. A send that starts after shutdown began still fails with client_closed.

The sends are tracked apart from the client's pending-promise queue, because flush() waits on that queue and a send in its retry backoff must not hold back event delivery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@mayteio mayteio added the posthog-review label Oct 27, 2026 — with PostHog
@posthog posthog Bot removed the posthog-review label Oct 27, 2026
…try-After on a failed body read

Shutdown now runs the core flush at once and waits for email sends in flight next to it, under the same deadline, so a slow send can no longer use up the budget for queued events.

When the headers of an error answer arrive but the body read fails or times out, the send now keeps that status and its Retry-After, so the normal retry rules apply. A failed body read on a 2xx answer stays a retryable network error. The body is still cancelled when the read passes the deadline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@mayteio mayteio added the posthog-review label Oct 27, 2026 — with PostHog

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed e6958e4: no findings.

This Standard review started from the posthog-review label. Comment @posthog review --deep for a Deep review, or @posthog help to see all commands.

@posthog posthog Bot removed the posthog-review label Oct 27, 2026
@mayteio mayteio added the stamphog label Oct 27, 2026 — with PostHog

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not approved yet — waiting on the conditions below.

Re-add the stamphog label to request another review once you have addressed this.

stamphog declined to auto-review this pull request because of the size gate. It has 812 substantive lines in the global area, which is over the 800-line ceiling (8 files, or 1231 lines across 12 files once docs, generated files and snapshots are counted). The other gates (prerequisites, deny-list and tier) passed, so size is the only reason for the refusal.

You can ask a human reviewer to look at it. Or you can split it into smaller pull requests, for example moving the parseRetryAfterMs cap change in packages/core into its own PR, which should bring the remainder under the ceiling.

  • posthog[bot] reviewed the current head.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✗ too large for auto-review (812L substantive in global — ceiling is 800L; 812L, 8F total, 1231L/12F incl. docs/generated/snapshots)
tier ✓ T1-agent / T1d-complex (1231L, 12F, two-areas, feat)
stamphog 2.6.1 .stamphog/policy.yml @ unknown · reviewed head e6958e4

@stamphog stamphog Bot removed the stamphog label Oct 27, 2026

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good; no qualifying findings. Verdict: correct.

`posthog.emails.send()` now posts to `/api/projects/@current/messaging/send/email/` with the template ID in the body as `template.id`, instead of the template-scoped route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
`posthog.emails.get(id)` reads `/api/projects/@current/messaging/emails/{id}/` and resolves to `{ data, error }`, where `data` is `{ id, status, createdAt, statusAt, reason }`. It retries network errors, rate limits and an unavailable service like `send`, which now shares that attempt loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
@mayteio
mayteio added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit c705824 Oct 30, 2026
80 of 81 checks passed
@mayteio
mayteio deleted the posthog/node-transactional-email-send branch October 30, 2026 10:28
eli-r-ph added a commit that referenced this pull request Nov 2, 2026
* test(browser): run deployment compatibility engines in parallel (#5384)

(cherry picked from commit 670189fb6a3a25944591fd5d638c652884ff86da)

* fix(node): stop esbuild failing when @opentelemetry/api is not installed (#5422)

Read the active span from the global registry of @opentelemetry/api v1. Do not import the optional peer. A literal import made esbuild fail the build when the peer was not installed. A variable import makes webpack warn and drop the module.

Add a test that bundles the built ESM and CJS entrypoints with esbuild when @opentelemetry/api cannot resolve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 0d603b98-9825-4f1c-8261-e50c33c8a122

Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
(cherry picked from commit b5036c46ccef4f653a9cb13b32543e3fa2a45c6d)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 196b7f9716bfba61ff8f94440823ddd4d6f9851a)

* chore: clear the Coherence spec problems reported on every PR (#5303)

* chore: clear the Coherence spec problems reported on every PR

Drop two commit ids from the add-an-invariant practice that exist in no branch of this repo, and give the two Otel spec bullets a name so spec --check passes.

Generated-By: PostHog Desktop
Task-Id: 822cb54b-55fa-4576-a107-1e406f72d9de

* chore: cite the Coherence adoption merge commit in place of its lost branch commits

ddaaf6808 is the squash merge of the PR that held 187a5c5c7 and 8922ab259, so the practice keeps its evidence and the citation resolves on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 4189fcb8-6fd5-428d-8c5f-4314d28e4dac
(cherry picked from commit 2e98ca8d6e44ed9d73fba85567b7f5de63e80b7d)

* fix(browser): stop parsing persistence on every capture() for Meta identifiers (#5429)

* fix(browser): only re-read Meta identifiers when persistence storage changed

capture() refreshed $fbc and $fbp from storage on every event, and every
persistence write did the same. Each refresh parsed the whole persistence
entry, and on localStorage+cookie it also wrote the entry back. With many
feature flags this made click handlers slow (#5428).

The refresh now compares the raw storage text with the text seen when the
identifiers last matched storage, and parses only when it differs.

Adds capture-hot-path tests that count parses of the persistence entry per
capture, so CI fails if hot-path storage work comes back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 6ab57ee6-6279-4378-b074-ed4f92849780

* chore(browser): write mangled property names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 6ab57ee6-6279-4378-b074-ed4f92849780

* fix(browser): skip Meta identifier refresh while disabled, and remember the pre-parse snapshot

refreshMetaIdentifiers() read storage even when persistence was disabled. It now returns first.

A refresh now remembers the storage text read before the parse, so a sibling write that lands during the parse is seen on the next refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 6ab57ee6-6279-4378-b074-ed4f92849780
(cherry picked from commit 103494838c69ebb9457bcaa6567a437118d7f1ec)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 64f8a4325bde1b2c00338a1c13ba6c9bbbfa9a4f)

* fix(replay): enable synchronous fetch by default for new cores (#5335)

* fix(replay): enable synchronous fetch by default for new cores

* docs(types): correct replay sync fetch default changeset

(cherry picked from commit cb34fe03c49feb636ea4537f6f6b05144d163dac)

* chore: update versions and lockfile [version bump]

(cherry picked from commit dfff34b269e4aad905c7763260f011f982a4d421)

* chore(next): fix test lint errors (#5317)

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
(cherry picked from commit cb0482aad64d91d766888f8c8548fdd515018611)

* test(browser): record synchronous replay fetch in current-core goldens (#5437)

#5335 updated 6 of the 20 __preview_replay_sync_fetch values per file; this updates the remaining 14 in replay snapshot payloads.

(cherry picked from commit 7e3a5e36babca74a8f196822bc3758016783dbe0)

* feat(llma): support per-item offline evaluation models (#5438)

(cherry picked from commit acdbdd2123cb379fae9f0615ee0e9ef627fbe8f9)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 199de5e2f5c8159a6b47e215e09515a78b973f27)

* fix: Surveys: an optional rating question with response-based branching throws "The response type must be an integer" when skipped (#5279)

* Fix #5278: Surveys: an optional rating question with response-based branching throws "The r

* fix: complete surveys when skipping final optional ratings

* fix: adapt optional rating survey fix to shared renderer

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dustin Byrne <dustin@posthog.com>
(cherry picked from commit d47c184b03040d6034bb15e7f7a0dcbd9b9a909f)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 615a550f3916eeac97e8546021d4aeb6f39913de)

* feat(react-native): add projectToken and deprecate apiKey (#5436)

* feat(react-native): add projectToken and deprecate apiKey

Rename the internal apiKey names in core and RN to projectToken.

* test(browser): record synchronous replay fetch in current-core goldens

#5335 updated 6 of the 20 __preview_replay_sync_fetch values per file; this updates the remaining 14 in replay snapshot payloads.

(cherry picked from commit 43ad061185c7f8b0a36ed87bb6a28214d4224e9d)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 183350588f47fcc8a983c37db33e3da5adaa362b)

* chore: upgrade posthog-android to pull in OkHttp 4.12.1 (#5441)

(cherry picked from commit 39ff01a86a20ca086e7b5dbbbd938e9d2115741b)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 1c165ccfee9d9b98dea93982cbd37bec8666fe5c)

* feat(browser): support latest configuration defaults (#5405)

* feat(browser): support latest configuration defaults

* docs(browser): regenerate latest defaults API reference

* test(nextjs): restore Next 16 fixture and dependency cooldown

* fix(browser): report resolved latest defaults date on events

* refactor(browser): derive latest defaults date from supported dates

(cherry picked from commit 31500798797e35187ca0a61bcf2af24d6ba45a96)

* chore: update versions and lockfile [version bump]

(cherry picked from commit b98cf1f29a232e0ddb488bb2bd822c762cb2f270)

* chore(react-native): require @posthog/react-native-plugin 2.12.7 or newer (#5445)

(cherry picked from commit b9fe0abf6f9c335b6ca49d9fb496662cca5806e5)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 87bca7a47ed4f12724c0d4b51fad759f721dad7b)

* perf(rrweb): port upstream mutation-buffer O(n²) fix (fixes #5227) (#5244)

* perf(rrweb): port upstream mutation-buffer O(n²) fix (fixes #5227)

Port the processBufferedMutations algorithmic core from upstream
rrweb-io/rrweb PR #1652 (merged 2026-09-17 by @eoghanmurray). The
addList-based drain used to tail-rescan every pass, so a single render
mounting many sibling nodes (e.g. a 50x35 table ~13k nodes) blocked the
main thread for ~10 s. The new topological-order drain iterates
this.addedSet with dom.previousSibling / dom.lastChild / dom.nextSibling
to reach a node whose parentId is already in the mirror BEFORE touching
its children, so pushAdd never defers onto a secondary queue that needs
rescanning. Nodes whose parent cannot be resolved for this emission land
in missingParents so their descendants early-out through the same set —
preserving the previous 'escape the dead while loop' guarantee without
the O(n²) cost.

PostHog customizations stay intact. pushAdd keeps isBlockedAtEmission,
shadow-host reparenting, serializationOptions caching,
canvasMaskingConfigured, iframe/stylesheet attach callbacks and the
cross-origin iframe shadow fix from #5150. It now returns boolean so
the new driver can mark deferred subtrees without silently dropping
nodes. mapRemoves is still drained before pushAdd so the reparent-
detection order documented in record/index.ts is preserved.

Added three untainted-prototype accessors to @posthog/rrweb-utils —
previousSibling, nextSibling, lastChild — matching the existing
getUntaintedAccessor('Node', ...) pattern. The new drain reads sibling
pointers in the hot path and native .previousSibling would bypass the
Angular Zone taint defense parentNode already uses. All three are added
to testableAccessors.Node so taint detection still fires if any of them
are patched by third-party code.

One pre-existing integration snapshot (record integration tests >
should record after DOMContentLoaded event) is updated to reflect the
new emission order of the standalone type:1 Load event, which upstream
rrweb #1652 also reordered. The event stream remains well-formed and
replayable because mutations stay in parent-before-child topological
order.

DoubleLinkedList class and the unused Optional type import are
removed — they were only referenced by the pre-fix drain loop.

New regression test in mutation-child-traversal.test.ts mounts 500
rows x 3 cells (~2000 nodes) in a single render and asserts every
emitted add has a resolved parentId plus a fully drained addedSet —
guards against the pre-fix regression where the 'escape the dead while
loop' fallback dropped entire subtrees once the addList rescan budget
blew up.

Attribution — algorithmic approach ported from upstream commits that
landed in rrweb-io/rrweb#1652:
  565e390 Iterate over the added nodes in 'one pass'
  90d4b01 Performance oriented refactor focusing on large-batch scenario
  c013727 Utilize lastChild to avoid crawling through hundreds of nodes
  325e211 Skip a step using existing nextSibling

* fix(rrweb): shadow DOM walk-up + warning + changeset per @TueHaulund review

Addresses all five review comments on PR #5244.

1. Shadow DOM content was silently dropped. When a node whose parent is
   a ShadowRoot gets handled before the shadow host, the walk-up loop's
   addedSet lookup never resolved — the walk-up stopped at the shadow
   root while pushAdd translates ShadowRoot -> host for the parentId.
   Result: shadow children emitted with parentId -1 and the push failed
   silently. Fix: translate ShadowRoot -> host inside the walk-up loop
   AND the missing-parents propagation step, mirroring pushAdd. The
   existing 'should record moved shadow DOM 2' integration test is the
   regression that catches this and passes with the fix.

2. Reverted the integration.test.ts.snap change (Load event reorder).
   The ordering is environment-dependent locally for me, but per Tue's
   review the original snapshot passes in the CI environment and the
   updated one failed, so I defer to that.

3. Added a basic jsdom correctness test asserting the
   parentId-resolvable invariant for every emitted add. Marked it
   explicitly as a weaker coverage test — the strong regression lives
   in integration.test.ts > 'should record moved shadow DOM 2' which
   needs the puppeteer harness. A full port of upstream rrweb #1652's
   mutation.test.ts fixture suite is a reasonable follow-up iteration
   if the review wants more.

4. Added console.warn when a node is deferred past this emission,
   matching upstream rrweb's phrasing. Silent drops here historically
   masked the shadow DOM regression; the warning means future
   regressions announce themselves in the browser console.

5. Added a changeset bumping posthog-js + @posthog/rrweb +
   @posthog/rrweb-utils so release-please actually publishes the fix.

* test(rrweb): regression bench for long sibling runs under single parent (#5227)

@yuetong3yu reported a second independent repro on 2026-10-15 (Svelte 5 +
bits-ui Portal, ~50k empty comment/text anchors as direct children of
<body>, scaling ~n^1.8 on 1.438.7). The port of upstream rrweb-io/rrweb#1652
in this branch drains addedSet in topological order and never re-queues,
so per-node cost should stay flat.

This test locks the invariant: 500-node vs 5000-node batch under one
parent, assert per-node drain stays within 5x (well above jsdom noise,
well below the pre-fix n^1.8 regression). Also covers mixed
comment+text+element shape and the no-silent-drop property.

No src/ changes.

* fix(rrweb): sanitize masked-node descriptor in diagnostic warn (@marandaneto)

The warning added in 8aeafb2a to surface deferred nodes passed `n`
directly as the second console.warn arg. Verified against
`rrweb-plugin-console-record/src/stringify.ts` lines 153-155:

    } else if (value instanceof Node) {
      if (value instanceof HTMLElement) {
        return value ? value.outerHTML : '';

With console recording enabled, the plugin stringifies any `Node`
argument via `outerHTML` — the diagnostic would persist the raw
masked content into a `rrweb/console@1` event. Reviewer-reproduced
on 2026-10-21 via the exact-head `review-5244-privacy.test.ts`
scenario (unblock container + insert `rr-mask` before an unmirrored
sibling → masked plaintext in the console payload).

Fix: build a sanitized descriptor from `tagName.toLowerCase()` + the
`nodeType` code and pass that string instead. The warning still
tells operators that a node was dropped (the reason the warn exists
after @TueHaulund review) but can no longer leak masked DOM to a
console-record consumer.

Also adds `test/record/review-5244-privacy.test.ts`, a static
regression test that greps the warn block for the pre-fix shape
(`, n,` / `, n)`) and asserts the descriptor + rationale comment
survive future refactors. Static-only so the vitest harness in
`packages/rrweb` can run it without a browser; CI covers it.

Reported-by: Marco Antonio Alvarez <marandaneto>
Thanks for the privacy catch on the diagnostic.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

* test(rrweb): fix stale DOMContentLoaded Load-event snapshot ordering

The should record after DOMContentLoaded event snapshot carried
the pre-#4976 event order where `init()` ran synchronously inside
the DOMContentLoaded listener. PR #4976 deferred `init()` via
`setTimeout(init, 0)` in `src/record/index.ts` so page-level
non-capture DOMContentLoaded listeners (mask/block classes) can run
before the snapshot. The deferral means the window `load` event
reaches `wrappedEmit` *before* `init()` runs `takeFullSnapshot`,
so the `type: 1` (Load) record now follows the `type: 4` (Meta)
and `type: 2` (FullSnapshot) records instead of preceding them.

The snapshot update reflects the actual emission order the
production code produces. Verified locally with
`vitest run test/integration.test.ts` (50/50 pass).

This change is independent of the mutation-buffer port in this PR;
isolated it rather than bundling so the diff stays reviewable.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

* test(rrweb): address mutation ordering review feedback

* fix(rrweb): address TueHaulund review on #5244

Six changes, one logic tweak, one test rewrite:

- src/record/mutation.ts: one summary console.warn per emit() instead
  of one warn per dropped node. Per-node warns cascade through
  subtrees (a 13k-node table loses its parent -> 13k warn lines, and
  with console recording on those lines land in the replay).

- src/record/mutation.ts: comment on the pushAdd return value now
  says "dropped" instead of "deferred" (the pending set is cleared
  at the end of emit, nothing retries it).

- src/record/mutation.ts: strip reviewer names and PR references from
  code comments. History belongs in the PR description, not the
  source tree.

- src/record/mutation.ts: match upstream rrweb's self+ancestor exempt
  for movedSet when deciding whether to drop an addedSet entry.
  Upstream uses isSelfOrAncestorInSet here; we were only checking
  ancestors.

- .changeset/rrweb-mutation-buffer-on2-fix.md: drop reviewer credit
  from the public CHANGELOG entry, keep the behavior description.

- test/record/review-5244-privacy.test.ts: deleted. Replaced by
  test/record/mutation-drop-warn-is-sanitized.test.ts, which spies
  on console.warn and asserts no Node argument and no masked content
  leaks, independent of source grep.

- test/record/mutation-child-traversal.test.ts: dropped the basic
  drain correctness test — the 15 ordering tests ported from
  rrweb-io/rrweb#1652 now cover the same invariant. Removed the
  elapsedMs < 5000 wall-time gate; the addedSet-residue assertion
  is the structural proof.

- test/record/mutation-sibling-run.test.ts: dropped per-node timing
  comparison across batch sizes (flaky under GC jitter). The new
  shape asserts residue and served-count invariants instead.

Local vitest run: 38/38 pass across the 8 mutation test files touched.
The three mutation.test.ts snapshot failures introduced in
02916d1f4 are untouched and remain for the author of that change.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

* fix(rrweb): drain walk skips IGNORED_NODE siblings (fasyy612 review)

The forward sibling walk inside the topological drain broke on the
first sibling not in addedSet. But getNextId skips past IGNORED_NODE
siblings when computing nextId, so a node inserted BEFORE an ignored
sibling (e.g. a slimDOM-filtered <script>) could be dropped when the
next new sibling sits AFTER the ignored node — the walk would stop
at the ignored sibling and never reach the later addition.

The ported upstream #1652 fixtures all exercise contiguous addedSet
siblings and hit the lastChild jump above the walk, so they miss
this path entirely. @fasyy612 flagged it with the right fix shape:
probe past mirror.getId(ns) === IGNORED_NODE siblings before deciding
to break, matching getNextId's own loop.

New fixture at test/record/mutation-ignored-sibling-skip.test.ts
covers both the positive case (sibling after ignored node still ships)
and the termination case (sibling after ignored node not in addedSet
and the walk stops instead of looping).

Local vitest: 40/40 pass across the 9 mutation test files.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

* fix(rrweb): three test fixes per TueHaulund second-pass review

- test/record/mutation-drop-warn-is-sanitized.test.ts: deleted. The
  test called `console.warn` itself and asserted on that call, so it
  did not exercise the mutation buffer and would still pass if the
  real warn leaked a node. The real sanitization is now a one-line
  `console.warn(string)` that cannot carry a Node argument by
  construction; a self-referential test on top of that has no
  catching power. Per @TueHaulund's offer to delete if a real repro
  is a pain.

- test/record/mutation-ignored-sibling-skip.test.ts: rewritten to
  actually hit the bug @fasyy612 flagged. The previous fixture
  (a) added the <script> in the same batch, so it was not yet
  IGNORED_NODE when the walk ran, and (b) put the new node as
  lastChild, so the lastChild jump above the walk skipped the walk
  entirely. Confirmed by reverting the probe-past-IGNORED fix
  locally: the new fixture now fails on the pre-fix walk and passes
  on d80c33fbe. The three conditions that must line up are called
  out in a comment at the top of the file so the next refactor does
  not quietly weaken the test.

- test/record/mutation-sibling-run.test.ts: the previous
  `addedSet.size === 0` residue checks could never fire because
  `emit()` swaps in a fresh empty addedSet before the drain runs.
  Replaced with sibling-lookup counts via a patched dom.previousSibling
  / dom.nextSibling / dom.lastChild — lookups-per-node must stay
  flat as batch size grows 10x. This is the invariant that actually
  caught the pre-fix ~n^1.8 scaling in reports. Removed the symmetric
  residue check in mutation-child-traversal.test.ts for the same
  reason.

Local vitest after the three fixes: 36/36 pass across the eight
mutation test files (the sanitization file is gone). The ignored-
sibling test confirmed to fail without the probe-past-IGNORED
patch.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

* fix(rrweb): scrub comment history, tighten assertions, interleaved-IGNORED guard

Follow-up to third-pass review on #5244.

Comment hygiene across mutation.ts, utils/src/index.ts, and the four
mutation-* test files: drop reviewer handles, PR numbers, and commit
SHAs from inline comments. Replace 'defer' with 'dropped' where the
code path actually drops nodes. Remove the stale addList-era narrative
in genAdds.

mutation-sibling-run.test.ts: reframe the test as a scaling guard on
the new drain rather than a direct regression on the old addList path
(which never called the sibling helpers). Fix the scaling-margin
narrative — n^1.8 total is ~6x per node for a 10x batch, not ~63x.

mutation-child-traversal.test.ts: assert exact add count (3500 =
500 rows + 1500 cells + 1500 text nodes) and parent-before-child
ordering by id, instead of the always-passing 1000 lower bound.

mutation-ignored-sibling-skip.test.ts: drop the always-zero
addedSet.size residue check — emit swaps in a fresh addedSet before
the drain so the check cannot fail.

mutation.ts drain: backward fast path at line 436 now probes past
IGNORED_NODE siblings symmetric with the forward walk at line 476.
Without this, slimDOM-ignored comments or scripts interleaved between
new siblings force the drain back to walk-up/descend per node,
regressing to O(n^2).

mutation-interleaved-ignored.test.ts (new): scaling guard with
<script>-interleaved siblings; per-node lookup count stays flat as
batch grows 10x.

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>

---------

Signed-off-by: Abd Alrahaman <abdarahman10555@gmail.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 52c84e28c35fc4041b55dbc3aa8b0b5a97e33026)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 8e3b8f57d72906d48426133c29f35e84b2065266)

* ci: run the sourcemap plugins through the error tracking harness (#5402)

* ci: run the sourcemap plugins through the error tracking harness

Packs the plugins and the SDKs they are tested with, then runs PostHog/error-tracking-harness
against them: real posthog-cli releases, real bundlers, a mock PostHog and an app whose
exceptions must resolve to their source lines. The image is pinned by digest and runs with no
network. Advisory until the matrix has been quiet for a while.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: pull the harness image anonymously

The package is public, like sdk-test-harness-v2, so the job needs no registry login and
runs with contents: read only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: pin merged lifecycle harness image and use named overrides

* ci: select affected error tracking fixtures and bind current core

* ci: bind complete fixture dependencies in error tracking harness

* ci: prepare selected harness fixtures in a subject image

* test(ci): describe prepared harness image smoke checks

* ci: pin published prepared-subject harness image

* ci: exercise lazy exception autocapture with PR tarballs

* ci: run fixed plugin smoke suite through reusable harness

* ci: build pinned harness source for PR smoke tests

* ci: upsert smoke results as a PR comment

* ci: pin published error-tracking harness image digest

* ci: exercise Next 16 smoke and secure PR reporting

* ci: pin published eight-fixture harness image

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit ed9ef472f156de463e1ec7317d46e96ce9fa5142)

* fix(browser): Refresh identity on bfcache restore (#5427)

* fix(browser): Refresh identity on bfcache restore

Generated-By: PostHog Desktop
Task-Id: dd368b5c-40fc-49ac-9fc0-4c3c321bfb36

* fix(browser): Update mangled property names for bfcache identity

Generated-By: PostHog Desktop
Task-Id: dd368b5c-40fc-49ac-9fc0-4c3c321bfb36

---------

Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
(cherry picked from commit 8a9a0661c6ccc21f1397a495855031e44fe7de49)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 90c73424ee622071d01bb2fb59ee663d0a6fd50e)

* fix: Expo 57 example: pnpm install fails with ERR_PNPM_TRUST_DOWNGRADE (#5443)

* Fix #5442: Expo 57 example: pnpm install fails with ERR_PNPM_TRUST_DOWNGRADE

* test: remove Expo resolver configuration assertion

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dustin Byrne <dustin@posthog.com>
(cherry picked from commit 6662c418aee37ae0c61bb2f48fec7ab86caf20a9)

* chore(react-native): deprecate flag APIs removed in the next major (#5431)

* chore(react-native): deprecate flag APIs removed in the next major

* chore(react-native): keep getFeatureFlagDetails, deprecate useFeatureFlagWithPayload

Add doc summaries to the deprecated flag APIs so the reference shows them.

* chore(react-native): deprecate overrideFeatureFlag in favor of updateFlags

(cherry picked from commit 96d7ff2e394126e2bd03a2422f60b5892a85d87f)

* feat(browser): add a single-tag SDK loader (#5406)

* feat(browser): add a single-tag SDK loader

* fix(browser): complete loader queues and report configuration errors

* feat(browser): support deferred initialization in the script loader

* docs(browser): clarify optional loader crossorigin attribute

* fix(browser): preserve SDK defaults and track loader build inputs

* fix(browser): pair loader aliases with immutable SDK releases

* test(browser): record static-loader deployment goldens

* test(browser): exercise automatic loader in deployment snapshots

* test(browser): refresh loader goldens after merging main

* fix(browser): preserve named loader initialization in automatic mode

(cherry picked from commit 285d874b7bc5914f3d7b0caa7006a3ba1a480b64)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 28b511b85c8a4d48ab4dd46a70dc62dcd133b002)

* feat(browser): add opt-in autocapture field values (#5269)

* feat(browser): add opt-in autocapture field values

* test(browser): cover opted-in autocapture values in compatibility matrix

* fix(browser): respect slot ancestry when capturing input values

* fix(browser): preserve autocapture events when value predicates throw

* fix(browser): respect autocapture ignorelist along slot ancestry

* fix(browser): respect selected option autocapture exclusions

* perf(browser): skip value privacy checks when text is masked

* fix(browser): preserve value capture scope across shared autocapture

(cherry picked from commit 950d03423605d1567c90a3f27f50d4603a89ae45)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 6d017a9bb225ebf1da331f4753b2e6c76ec4eeba)

* test(browser-common): use trimmed mean in console log perf tests (#5463)

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 7fdc0aa612d134c1b3e5bb974bdac1b56f248fdb)

* feat(mcp): add a sendInitializeEvent option (#5401)

* feat(mcp): add a captureInitialize option

captureInitialize: false stops $mcp_initialize. The option is on by
default. Many clients reconnect before every few tool calls, so the
handshake event can outnumber $mcp_tool_call.

With the option off, the initialize wrapper skips captureEvent. Nothing
else changes: it still mints the session token and records the
negotiated protocol version, so tool calls keep their sessions and
client identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(mcp): rename captureInitialize to sendInitializeEvent

PostHogMCP already has a captureInitialize() method that sends the
event by hand. An option with the same name next to that method makes
readers link the two. The new name says what the option controls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(mcp): name the PostHog screens that read $mcp_initialize

MCP onboarding and the users and sessions tiles of the default MCP
dashboard read $mcp_initialize. The README now says that they show no
data while sendInitializeEvent is off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 8faad6aa2508b38959cbd27196aa805bf6fa5ab7)

* fix(browser): fall back to Math.random when crypto.getRandomValues throws (#5222)

* fix(browser): fall back to Math.random when crypto.getRandomValues throws

Firefox throws an OperationError when its random source fails. uuidv7() did not catch it, so the throw escaped from capture() into the host page and the event was lost. The generator now uses the existing Math.random fallback when the call throws.

Generated-By: PostHog Desktop
Task-Id: 3f144ec2-2e2c-413c-b864-11ca8ca05308

* test(browser): assert the uuidv7 fallback uses Math.random

The test checked that two UUIDs differ, but the counter alone makes them differ. A spy on Math.random now proves the fallback filled the buffer. The Math.random note moves into a doc comment on weakRandomValues.

Generated-By: PostHog Desktop
Task-Id: 8662b8b4-5fad-4c39-baef-5a6a4a9e36d2

---------

Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
Co-authored-by: Steven Shults <steven@posthog.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 6d12d24ed24b2846415dbd95fc5d7ccf57779a99)

* chore: update versions and lockfile [version bump]

(cherry picked from commit fd7d0c9cbab001e3aabcd8c3162eeccc4ff73e13)

* fix(react-native): Capture touch autocapture events on Fabric instances (#5466)

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 8c136a8608187dc77b97cc4724639755b37d3c85)

* chore: update versions and lockfile [version bump]

(cherry picked from commit a3e9ec3d274e64f8cdfbb29e99c1ee385d34cf8f)

* feat(mcp): add a sendToolsListEvent option (#5404)

* feat(mcp): add a sendToolsListEvent option

sendToolsListEvent: false stops $mcp_tools_list. The option is on by
default. Clients list tools on every reconnect, so the listing event is
about as common as $mcp_tool_call.

All three places that send the event go through captureToolsListEvent,
which skips the capture when the option is off. That also drops a failed
listing's $exception. Nothing else changes: tools keep their injected
arguments, and the virtual tools stay listed.

The name says "event" to match sendInitializeEvent.
PostHogMCP.captureToolsList() already captures the event by hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(mcp): gate $mcp_tools_list with a plain if, like the initialize event

The captureToolsListEvent wrapper read the tracking data again through
its first argument. Now each of the three emit points checks
sendToolsListEvent directly, as handleInitializeRequest does for
sendInitializeEvent. getTracedToolsList gets the flag as an argument for
its failed-listing path. The behaviour does not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 68336dfb097a78e08041c77f72bbcc59b6958e04)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 8dc2e88f6580c6f46107385bdf193f21b467bab7)

* feat(node): add request context to OpenTelemetry spans (#5314)

* feat(node): add OpenTelemetry request context processor

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* feat(node): add signal-controlled context lifetimes

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(node): preserve exception snapshots and fresh scopes

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(node): scope NestJS span context to the response

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* refactor(node): share abort signals for request lifetime

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(node): enrich verified request server ancestors

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(node): expose context enrichment without tracing imports

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix: respect node span privacy and request lifetime

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(node): share context listeners across CommonJS and ESM builds

An app that uses require('posthog-node') and imports posthog-node/otel
loads two module copies. Each copy had its own listener registry, so the
incoming request span was not enriched. Keep one registry on globalThis.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9

* fix(node): keep request context after the response ends

Express and NestJS no longer end the request context when the response
finishes or closes. A promise or timer that the handler starts can
still belong to the same user action, so getContext(), captured events,
and new spans keep the request IDs as before. Apps that want a hard end
can still pass ContextOptions.signal.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9
(cherry picked from commit 096131dc7cf6115217996ff8fccace5598ed1e31)

Adapted for capture-v1: keep context options in the merged context scope;
pass the context snapshot after the level argument of buildEventMessage;
read context in the v1 _buildExceptionEvent and _prepareEventMessage; read
headers through readPostHogTracingHeaders; also copy context options into
the exception snapshot.

* feat: add next.js and nuxt server span context (#5315)

* feat(next): add optional server span context bridge

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* test(next): define sampler gap context boundary

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* feat(nuxt): add optional server request span context

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix(nuxt): enrich incoming spans at request entry

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* fix: share framework span enrichment without optional imports

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96

* chore(nuxt): use enabled clients in span context tests

Generated-By: PostHog Desktop
Task-Id: bfd18848-e498-4352-a58a-b9ba85de4198

* fix(next): keep nested context in span context callbacks

withPostHogContext passed a proxy that put the request identity back on
every call, so posthog.withContext inside the callback was ignored. The
callback already runs inside the request scope, so pass the client.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9

* fix(nuxt): keep application context in request scopes and errors

With requestContext on, the request scope now keeps properties from an
outer application context. The error hook now prefers the active
application identity over the saved header identity.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9

* fix(next,nuxt): keep request context for work after the handler

Match posthog-node: withPostHogContext and the Nitro request wrapper
no longer end the context when the handler returns or throws. Work the
handler starts keeps the request IDs.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9

* fix(next): share the Node.js client cache across webpack layers

Next.js 15 bundles instrumentation and App Router handlers in separate
webpack layers, each loading its own copy of clientCache.node.ts. That
gave each layer its own client for the same key, so the OTel span
processor (reading one client's context) and withPostHogContext
(writing another's) could disagree about the current request. Cache
clients on globalThis, keyed by Symbol.for, so every layer shares one.

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9
(cherry picked from commit e4df2d57bb242c2d5c107f4f8b0a9edc8557a749)

* fix(rrweb): port upstream shadow-root release on host removal (fixes #5419) (#5421)

* fix(rrweb): release removed shadow DOM hosts from the recorder

Port the shadow-root release from rrweb-io/rrweb#1958 (as shipped in rrweb 2.2.0), adapted to the fork's per-document teardown. Fixes #5419.

* fix(rrweb): release shadow hosts removed from blocked containers

Also adds removeShadowRootsIn to the shadowDomManager test mocks and a frozen remove/re-insert recording test.

---------

Co-authored-by: frostfire575 <191205836+frostfire575@users.noreply.github.com>
(cherry picked from commit 34833f2df9a6252a6dd03bcc19ca6af755a23953)

* fix(browser-next): settle pending captureImmediate when the extension is disposed (#5448)

* fix(browser-next): settle pending captureImmediate when the extension is disposed

deliverImmediate awaited ensureDelivery('immediate') before checking
cancellation. If shutdown disposed the analytics extension while the lazy
delivery loader was still pending, the immediate capture stayed unresolved
until the loader settled, possibly forever.

Race the delivery wait against a disposal signal so the capture resolves
with the existing cancellation summary as soon as the extension is
disposed. A loader that resolves later does not send the event.

Fixes #5093

* fix(browser-next): release per-capture disposal waiters after immediate delivery

* chore: add changeset

* chore: remove changeset for private @posthog/browser

---------

Co-authored-by: Guilherme Praça <247475208+guilherme-praca@users.noreply.github.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 9d3fbe6e4eff5cdad2e4ab96efded61740d64cbc)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 4044a5c9ce65e2bc031d435a75b1353690c8b276)

* feat(browser): add single-script installation (#5395)

* feat(browser): add a standalone classic-script entry point

* test(browser): run standalone snippet coverage in CI

* fix(browser): preserve script CSP nonces in lazy chunks

* refactor(browser): name the hosted entry script.js

(cherry picked from commit a0a29d6955db32eb58a5a85dc1f4a7320506fc08)

* ci(browser): publish standalone assets to the CDN (#5396)

* ci(browser): publish versioned CDN assets before npm releases

* fix(browser): retain CDN artifacts and publish immutable entries last

* refactor(release): isolate posthog browser S3 publication

* fix(release): report posthog browser S3 failures

* refactor(release): decouple browser S3 uploads from npm

* fix(release): audit browser S3 failure notifications

* fix(release): reject superseded browser alias promotion

* refactor(release): use script.js for browser assets

(cherry picked from commit 6fba0c4c373dcc4bde13ae50bb37e856bbdd8693)

* feat(browser): publish the experimental npm package (#5397)

* feat(browser): enable experimental v0 npm releases

* docs(browser): record initial distribution size baseline

* docs(browser): refresh CSP-aware CDN measurements

* chore(browser): simplify npm release validation

* fix(release): gate posthog browser npm publication independently

* refactor(release): use the shared npm matrix for posthog browser

(cherry picked from commit 5a21286ec19a6c2ee37fe8ed2e585a2f2b8b3f5e)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 0745e2a2d446e0be857d83cf45cbaf77b83e5fe2)

* feat(node): honor sendFeatureFlagEvent in evaluateFlags snapshots, with a per-read override (#5252)

* fix(node): respect sendFeatureFlagEvent in evaluateFlags snapshots

A client created with `sendFeatureFlagEvent: false` sends no
`$feature_flag_called` events from the single-flag getters, but reads
from an `evaluateFlags()` snapshot (`isEnabled()`, `getFlag()`) still
sent one per key. The snapshot accessors take no per-call option, so
the client option now decides, defaulting to true as before. Access
tracking for `onlyAccessed()` is unchanged, and the single-flag
getters keep their per-call override.

* feat(node): add a per-read sendFeatureFlagEvents option to evaluateFlags snapshots

`isEnabled()` and `getFlag()` on an `evaluateFlags()` snapshot now take
`{ sendFeatureFlagEvents }`, like the single-flag getters. The per-read
value wins, then the client's `sendFeatureFlagEvent` option, then `true`.
One client helper resolves this for the snapshot reads and the
single-flag getters.

When events are off for a read, the snapshot sends no
`$feature_flag_called` event, missing keys included, and leaves the
dedupe cache untouched, so a later read that sends events still reports
the flag. The key is still marked accessed, so `onlyAccessed()` capture
enrichment is unchanged. Filtered snapshots from `only()` and
`onlyAccessed()` honor the option the same way.

Update the option docs and the public API references.

* fix(openfeature): follow the client's sendFeatureFlagEvent option in the Node provider

`PostHogServerProvider` defaulted its `sendFeatureFlagEvents` option to
`true` and passed it on every `getFeatureFlagResult()` call. That per-call
value overrode a client created with `sendFeatureFlagEvent: false`, so
every flag evaluation through the provider still sent
`$feature_flag_called`.

Leave the option undefined when it is not set, so the client option
decides. An explicit provider option still wins. Every posthog-node
version in the peer range resolves an undefined per-call value to the
client option, then `true`.

(cherry picked from commit 503c3ea1ee79d3ff8c6cce90c9e455a0455af50a)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 6f11d8ec6aefd127baf86125f778de23de02913b)

* feat: add conversations open() and close() (#5467)

* feat: add conversations open() and close()

* fixes

* terser

(cherry picked from commit afde45e3d38272d1512c2f5de66e9a249895ade2)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 2fc5f976d8356bd8183cebdcdb47d304d3fb9da2)

* feat(node): opt-in posthog-js cookie fallback for request context (#5270)

* feat(node): read the posthog-js cookie when tracing headers are missing

The Express and NestJS integrations read the distinct ID and the live session ID from the ph_<token>_posthog cookie as a fallback for each missing tracing header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* fix(node): use core cookie helpers and respect opt-out

Use getPostHogCookieName and cookieStoreFromHeader from @posthog/core, ignore the cookie when the consent cookie opts out, and compare timestamps with an absolute difference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* fix(node): make the posthog-js cookie fallback opt-in and identity-safe

Add the readPostHogCookie option (off by default), because the server cannot see an opt-out that posthog-js keeps in localStorage. Read the cookie only when neither tracing header is present, take the distinct ID only for identified users so anonymous visitors stay personless, and accept the older two-item $sesid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* feat(node): allow a custom session idle timeout for the cookie fallback

readPostHogCookie also accepts { sessionIdleTimeoutSeconds } for projects with a custom posthog-js session_idle_timeout_seconds. The option doc lists the unsupported posthog-js configurations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* fix(node): clamp the cookie session idle timeout like posthog-js

Clamp sessionIdleTimeoutSeconds to 60 seconds through 10 hours, the bounds posthog-js applies, and test the option parsing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* feat(node): honor opt-out by default for the cookie fallback

readPostHogCookie accepts optOutCapturingByDefault, so a visitor without a consent cookie counts as opted out, like posthog-js with opt_out_capturing_by_default. Add a NestJS option gate test, an Express test that anonymous cookie visitors stay personless and an explicit distinctId wins, and regenerate the public API references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* fix(node): treat a zero idle timeout as the default and return null when off

sessionIdleTimeoutSeconds: 0 now falls back to 30 minutes, like posthog-js, and getPostHogCookieReadOptions returns null when cookie reading is off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 80f44d9e-704d-4f9c-93d2-bd37d55ab1c2

* fix(node): match browser cookie consent semantics

---------

Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 4b25f7f1d8fff0e442f6cf9403beec2b4a96b743)

Adapted for capture-v1: readPostHogTracingHeaders takes the cookie read
options, so captureTracingHeaders: false also turns off the cookie
fallback; the readPostHogCookie doc says so.

* chore: update versions and lockfile [version bump]

(cherry picked from commit 73d787a582d3c92b6ec29f3ceedd5e6abaf0bc29)

* fix(ai): capture an error event when a streaming OpenAI call fails before the stream opens (#5478)

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit aa4ed5deb82510af1b684988e4fe83739f02b7c2)

* chore: update versions and lockfile [version bump]

(cherry picked from commit a3187e23b2f65932c850a7e723474b3237df4325)

* fix(browser): keep the full URL when masking query params that contain ? or # (#5341)

* fix(browser): keep the full URL when masking query params that contain ? or #

Signed-off-by: Sebastian Turner <sebastiant3484@gmail.com>

* fix(browser): fully mask query values with nested question marks

---------

Signed-off-by: Sebastian Turner <sebastiant3484@gmail.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit de6b06f8a53faac5113ba979aa48472e6965a2b5)

* feat(Surveys): Implement survey popup delay (surveyPopupDelaySeconds)… (#5243)

* feat(Surveys): Implement survey popup delay (surveyPopupDelaySeconds) for React Native

* WIP fixing popup eligibility and delay bug

* Fix formatting of PostHogSurveyProvider.tsx

* Check for delay override flag before using default delay.

* fix(react-native): preserve pending survey delays and appearance defaults

* chore(react-native): release survey popup delay as minor

---------

Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit a96d286acf5b313af96beea1ebd7ce1b0a66c153)

* chore: update versions and lockfile [version bump]

(cherry picked from commit dfb2e002db81eee1889841d272b54e04f4c722f5)

* fix(node): keep local flag evaluation consistent with the server (#5471)

(cherry picked from commit 0058ef9664f27224de6377ec18d786bdc0e67e4d)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 4949cecefbaa621d017b2e2761a30a4d6151009c)

* chore: upgrade @posthog/coherence to 1.10.1 (#5432)

* chore: upgrade @posthog/coherence to 1.10.0

1.10.0 makes the Coherence PR comment say what each finding means and what to do, and marks the findings that are in files the pull request changed. The existing workflow gets the marks with no change, because the report reads the pull request's base from the GitHub event. The release-age exclusion moves to the new exact version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 4189fcb8-6fd5-428d-8c5f-4314d28e4dac

* chore: upgrade @posthog/coherence to 1.10.1

1.10.1 writes the PR comment in Simplified Technical English, folds explanations, colours the verdict, and adds icons. The release-age exclusion moves to the new exact version, and the lockfile changes only the Coherence entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 4189fcb8-6fd5-428d-8c5f-4314d28e4dac
(cherry picked from commit 2b0ae91bc43854a3a35d09604bdac1ef0f6b3a85)

* fix(ai): load @posthog/ai/otel without sdk-trace-base (OpenTelemetry JS 3.x) (#5439)

* fix(ai): load @posthog/ai/otel without sdk-trace-base

OpenTelemetry JS 3.x has no @opentelemetry/sdk-trace-base, so the runtime BatchSpanProcessor import crashed at startup. PostHogSpanProcessor now queues AI spans and exports them in batches through its own OTLPTraceExporter, with the BatchSpanProcessor defaults. All sdk-trace-base imports are now type-only.

Closes #5435

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: 6c8e40de-2d6f-465c-b51d-c5fd5ddef50e

* fix(ai): support both OpenTelemetry trace package layouts

---------

Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com>
Co-authored-by: Dustin Byrne <dustin@posthog.com>
(cherry picked from commit a22cbecd47f5a727747e1113c5c0be992cbeda1d)

* fix(browser): make test:typecheck pass and run it in check-types (#5210)

* fix(browser): make test:typecheck pass and run it in check-types

The browser test tsconfig is not strict. Two source files and three tests had type errors under it. Vitest does not check types, so nothing caught them.

Run test:typecheck from the browser check-types script, so CI runs it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e91bb021-a0e3-4e6f-abca-a7d22f162008

* fix(browser): hash sibling sources for the browser check-types task

test:typecheck compiles browser-next source and browser-common test helpers. Turbo did not hash those files for posthog-js#check-types, so a local cache could give a stale pass after an edit there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e91bb021-a0e3-4e6f-abca-a7d22f162008

* chore(ci): keep 8-letter chunk names distinct in the bundle size check

The strip-hash pattern masked any 8-character word, so analytics-delivery and analytics-internal both became analytics-********. The action then compared one file with the other and reported a false change. Mask only groups that contain an uppercase letter or a digit, as build hashes do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e91bb021-a0e3-4e6f-abca-a7d22f162008

* fix(browser): retain test typechecking after merging main

---------

Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 0ea261765e3bdddcc66019e5f0d403646edaf8a6)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 14dc382c5ed3171d3b387e768b619a7e7908a462)

* test(browser): synchronize replay compression before advancing clock (#5484)

(cherry picked from commit 8dba40ccba917292868b71873bbc4998a924498c)

* fix(react-native-plugin): require posthog-ios 3.92.7 (#5482)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit dfd56e6e567b46b074a25f0e598877594dd8bab6)

* chore: update versions and lockfile [version bump]

(cherry picked from commit c145829e6e8cc327272116191c03f4bbfdb87e30)

* chore: let the PostHog watcher close its own stale draft PRs (#5380)

(cherry picked from commit 1f6a0156d127dff5889728c16a39bd6a1b387d12)

* feat(browser): add a local bootstrap and preserve SDK namespaces (#5470)

* feat(browser): add a nonblocking hosted loader bootstrap

* fix(browser): load the SDK directly from the local bootstrap

* fix(browser): reject malformed bootstrap asset hosts

* docs(browser): keep usage documentation on posthog.com

* fix(browser): keep local bootstrap SDK updates automatic

* feat(browser): preserve selected SDK loader namespaces

* fix(browser): preserve deferred loader queues and improve diagnostics

(cherry picked from commit 41ae7fd024a582c811e85bae16e284467ae4ee3d)

* chore: update versions and lockfile [version bump]

(cherry picked from commit 67d874e9c47f83b39f32b12ccb3dba6c34e45416)

* feat(node): send transactional email from a template (#5418)

* feat(node): send transactional email from a template

Add posthog.emails.send() for PostHog transactional email templates, with the appHost, emailRequestTimeoutMs and emailRequestMaxRetries client options. Sends go to the app host with the project secret key and an idempotency key that every retry reuses. send() resolves to { data, error }.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: a0274fa0-d9be-48bf-b601-f153decf241d

* fix(node): match the email contract and keep long Retry-After waits

- A custom host without appHost now fails with missing_app_host, the code the cross-SDK contract in PostHog/posthog#120921 defines.
- The request deadline uses a referenced timer, so a short-lived script can't exit while it awaits a send whose injected fetch holds no handle.
- error.retryAfterMs keeps the full server Retry-After. parseRetryAfterMs in @posthog/core takes an optional cap for this; the 30 second retry ceiling still applies separately.
- The email send responses entrance in Node.spec.md declares control: none with its reason, which closes the coherence spec gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* fix(node): name 422 send checks validation_error and release late responses

- The template send route answers 422 for recipient_suppressed, sending_paused and sending_suspended as well as idempotency_key_reused. Only idempotency_key_reused is now invalid_idempotent_request; the send checks are validation_error, as the cross-SDK contract names them.
- A response that an injected fetch returns after the deadline now has its body cancelled, as the core transport does, so repeated timeouts don't keep pooled connections busy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* fix(node): fail email sends from a disabled client with client_disabled

A disabled client returned { data: { id: null }, error: null }, so a caller that treats a result without an error as sent dropped the email silently. It now sends nothing and returns the error client_disabled (name application_error), as the cross-SDK contract in PostHog/posthog#120921 defines. SendEmailResult.id is always the queued message ID, so its type is string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* fix(node): cancel a stalled email body read and refuse sends after shutdown

When an injected fetch answers before the deadline but its body read stalls, the email request now cancels the received body after the timeout, so it frees its connection.

After shutdown(), emails.send() now returns client_closed before any request, as the cross-SDK contract requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* fix(node): wait for email sends in flight when the client shuts down

EmailSender now tracks each send, retries included, and shutdown() waits for those sends within its existing timeout. A send that starts after shutdown began still fails with client_closed.

The sends are tracked apart from the client's pending-promise queue, because flush() waits on that queue and a send in its retry backoff must not hold back event delivery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* fix(node): flush events alongside email sends on shutdown and keep Retry-After on a failed body read

Shutdown now runs the core flush at once and waits for email sends in flight next to it, under the same deadline, so a slow send can no longer use up the budget for queued events.

When the headers of an error answer arrive but the body read fails or times out, the send now keeps that status and its Retry-After, so the normal retry rules apply. A failed body read on a 2xx answer stays a retryable network error. The body is still cancelled when the read passes the deadline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* feat(node): send transactional email through the single send endpoint

`posthog.emails.send()` now posts to `/api/projects/@current/messaging/send/email/` with the template ID in the body as `template.id`, instead of the template-scoped route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* feat(node): read a transactional email's status with emails.get

`posthog.emails.get(id)` reads `/api/projects/@current/messaging/emails/{id}/` and resolves to `{ data, error }`, where `data` is `{ id, status, createdAt, statusAt, reason }`. It retries network errors, rate limits and an unavailable service like `send`, which now shares that attempt loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* chore(node): regenerate references and spec for emails.get

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be

* docs(node): describe the email error name as a category

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
(cherry picked from commit c705824357b00a1187302224a58f478d1f652a54)

Adapted for capture-v1: shutdown waits for email sends next to the lane
drain and core flush; the backoff test mocks the v1 analytics endpoint
instead of /batch/.

* chore: update versions and lockfile [version bump]

(cherry picked from commit decaa166429ad781a53ad57853b8378d30fa65b3)

* chore(deps): bump the github-actions group across 1 directory with 7 updates (#5468)

Bumps the github-actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [step-security/harden-runner](https://github.com/step-security/harden-runner) | `2.22.1` | `2.22.2` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.1` | `7.0.2` |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.38.3` | `4.39.1` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.38.3` | `4.39.1` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `4.3.0` | `8.0.2` |
| [actions/setup-java](https://github.com/actions/setup-java) | `6.0.1` | `6.1.0` |
| [PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml](https://github.com/posthog/posthog-sdk-test-harness) | `1.15.0` | `1.20.0` |

Updates `step-security/harden-runner` from 2.22.1 to 2.22.2
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](https://github.com/step-security/harden-runner/compare/ccd8616d44fd3846e67624a50d5aad6d37bf2d25...dc2769abcc0fcfbadfc1df54081c1608579ef6b2)

Updates `actions/upload-artifact` from 7.0.1 to 7.0.2
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v7.0.1...cf430e030ddbb5b0abf93d22962f4752f3646cd9)

Updates `github/codeql-action/init` from 4.38.3 to 4.39.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...9b3254085494b55a0f7c4c2b3d2d52cc712ce370)

Updates `github/codeql-action/analyze` from 4.38.3 to 4.39.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/24c54180a607b1449ed407dd24f251e4e9147c8d...9b3254085494b55a0f7c4c2b3d2d52cc712ce370)

Updates `actions/download-artifact` from 4.3.0 to 8.0.2
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4.3.0...9000827ccba6bdab643e8b6fd33ac0654aef8333)

Updates `actions/setup-java` from 6.0.1 to 6.1.0
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/de7274f081f381c8f8158605e0321c36c376e2e6...b843ebf9b913146b38da2eaa7aeddf76074ae1ad)

Updates `PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml` from 1.15.0 to 1.20.0
- [Release notes](https://github.com/posthog/posthog-sdk-test-harness/releases)
- [Changelog](https://github.com/PostHog/posthog-sdk-test-harness/blob/main/CHANGELOG.md)
- [Commits](https://github.com/posthog/posthog-sdk-test-harness/compare/64ffa6ab19166541880c077d349abe18a7e42395...aa725c89eec72cb8ac75f4e418662bf2e161feb8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-java
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.39.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.39.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: PostHog/posthog-sdk-test-harness/.github/workflows/test-sdk-action.yml
  dependency-version: 1.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: step-security/harden-runner
  dependency-version: 2.22.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 1950c3cceff895310392be75ef51d1984f779665)

* fix(node): capture unhandled rejections when the host has its own listener (#5472)

* fix(node): capture unhandled rejections when the host has its own listener

In Node's default throw mode (and warn-with-error-code), posthog-node did
not listen for unhandledRejection and relied on Node escalating the
rejection to uncaughtException. A host with its own unhandledRejection
listener, such as Next.js, stops that escalation, so the rejection was
never captured.

The SDK now listens for unhandledRejection only while another listener
exists. Such a listener has already stopped Node's default handling, so
adding ours changes nothing. It tracks hosts that add or remove their
listener after init through newListener and removeListener. A rejection
captured this way and then rethrown by the host listener is not captured
again by the uncaught-exception handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkuJAD3n8f6Ra7L9p2UmPw

* fix(node): one capture per occurrence, and keep Node's behaviour, for host-handled rejections

Shares one set of process listeners across clients and bundled copies, with one capture per project. A rethrow, a
double delivery or a captureException from a framework hook counts once. Rejections wait a one-second grace period,
cancelled by rejectionHandled, and are sent on flush(), waitUntil, shutdown(), a fatal exit and beforeExit. React
and Next.js control-flow errors and AbortError rejections are skipped. Our listener is prepended so it sees the host's
listeners, and reproduces the runtime's handling when the host's listener disappears without an event (Bun).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkuJAAYPkxG7cuvaUbEGCf

* fix(node): run deferred rejection captures in their own async context, and send what a flush owes

Addresses the review of the host-handled rejection capture:
- A deferred capture runs in a snapshot of the async context the rejection happened in, so it reports that
  request's context and OpenTelemetry span, or none, ne…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants