Skip to content

fix(core): honor Retry-After on the OTLP export queues - #4726

Open
turnipdabeets wants to merge 43 commits into
feat/traces-node-mvpfrom
fix/otlp-honor-retry-after
Open

fix(core): honor Retry-After on the OTLP export queues#4726
turnipdabeets wants to merge 43 commits into
feat/traces-node-mvpfrom
fix/otlp-honor-retry-after

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

Two ways the OTLP export queues spend requests the ingestion endpoint has already told them not to send.

1. Retry-After was ignored. The endpoint can tell an SDK how long to wait before retrying. The logs, metrics and traces export queues each used only their own exponential backoff, so a project told to back off for two minutes kept sending.

This is conformance and defence-in-depth, not an urgent fix. PostHog's own capture path emits only 200/400/401/413/500 and never 429. The work that would have changed that, posthog/posthog#75090, was closed as stale in August without merging, and nothing has replaced it. Two reasons to do it anyway:

  • The sdk-specs logs and traces contracts require it unconditionally — "exponential backoff capped at ~30s, honoring Retry-After when present" — with no carve-out for the service not sending one yet. All three queues failed that requirement.
  • Capture is not the only thing that can answer a request. Customers front it with proxies, CDNs and load balancers, and any of those can return 429 with a Retry-After today.

2. Oversized batches were uploaded only to be refused. The endpoint caps the request body at MAX_REQUEST_BODY_SIZE_BYTES, applied after it decompresses — 10 MiB on the deployed ingestion service (charts shared/capture-logs/common.yaml). A batch over that could only ever come back 413, but the SDK uploaded it anyway — and the halving loop then re-uploaded progressively smaller versions, spending a full request on each attempt.

Note that the traces spec still describes #75090 as "in flight" in its Server-side contract requirement; that reference needs updating in sdk-specs independently of this PR.

Stacked on #4579 because the traces queue only exists there. The logs and metrics halves are independent of it and would apply to main unchanged.

Changes

Retry-After

Parsed once, in the shared OTLP sender, and surfaced to whichever queue is retrying.

  • parseRetryAfterMs accepts both wire forms — delta-seconds and HTTP-date — and returns undefined for anything it cannot parse, a date already in the past, or a non-positive delta, so the caller falls back to its own backoff. "10 minutes" is rejected rather than read as 10 seconds, and so is numeric-looking junk (-5, +5, 5.5), which Date.parse would otherwise read as dates in 2001.
  • PostHogFetchHttpError exposes it as retryAfterMs, guarded: headers.get is injected transport code, and a throwing one must not turn a retriable failure into an unhandled rejection.
  • The retry-later outcome of all four send wrappers gains an optional retryAfterMs. Additive, so nothing implementing or consuming these types breaks.
  • Each queue stores it and clears it on any other outcome, so one quota response cannot pin the delay for the rest of the process.

Three judgment calls worth reviewing:

  • The header is a floor, not a replacement. max(ownBackoff, retryAfterMs). Taking it literally would let a Retry-After: 1 turn a queue that had backed off to 30s into a hot loop; HTTP semantics are "not before this", which max satisfies in both directions.
  • Capped at five minutes. A quota window can legitimately be long, but an unbounded value from a misconfigured proxy would strand a queue for hours.
  • The inner fetchWithRetry loop stops when the header is present. That loop retries on a fixed short delay (fetchRetryDelay, default 3s) up to fetchRetryCount (default 3) times. Left alone it fired four requests inside the very window the queue was about to honour, so retryCheck now hands a Retry-After response straight to the queue-level backoff. A retriable response with no header still retries there as before.

Logs stores an absolute deadline rather than a duration, because the timer is not its only send trigger: the maxBufferSize size trigger and onReconnect() both start a flush directly, and both now check the window. onReconnect() no longer clears it — an online event means the network came back, not that the endpoint's rate limit expired, and browsers fire it on every network handover.

Metrics has no exponential backoff of its own, so there the header raises the next timer arm above flushIntervalMs.

Every send path, not just the timer

The first revision gated only the paths that arm a timer. A later review pass found three places where a send still went out inside the window. Each was reproduced with an executed failing test before it was touched.

  • posthog-node spent a span batch's whole retry budget inside the window. flushBackground() fires every flushInterval (10s default) while events are flowing, and node's flush() override drains spans alongside them. MAX_RETRIES_PER_BATCH is 8, so at that cadence the budget burned out in ~80s and the spans were dropped ~220s before the endpoint would have accepted them — Dropping 1 span(s): the ingestion endpoint failed 8 times in a row. A refusal that lands inside a window the endpoint already asked us to wait out is not evidence against the batch, so it no longer counts against that budget. The send itself is deliberately not suppressed: see "Why explicit flush still sends" below.
  • Logs armed a plain-interval timer after any explicit flush(). flush() leaves no timer behind, so the next capture is the one that arms it — at flushIntervalMs, inside the window. React Native takes this path on every foreground and background transition. _armFlushTimer now floors the delay by the remaining window.
  • Logs never ended the window on a successful explicit flush(). The clear lived on the background wrapper's .then, which flush(), flushWithTimeout() and shutdown() do not go through, so onReconnect and the size trigger stayed blocked for the rest of a window the endpoint had already stopped enforcing. The window is now recorded and cleared from the outcome, the way metrics and traces do it.

Metrics and traces also held the header as a duration rather than a deadline, so a timer armed while the wait was already part-served restarted the whole window instead of counting down the remainder. Both now hold an absolute deadline, matching logs.

parseRetryAfterMs additionally reads only the first value when two hops each append one — headers.get joins repeated headers as "60, 120" — while leaving an HTTP-date, which carries a comma of its own, intact.

A refusal that arrives inside an open window may push the deadline out, but never past MAX_RETRY_AFTER_MS from where the window was first installed. Sliding it forward without that ceiling meant a host flushing faster than the window kept it open forever, so the retry budget never advanced and the head batch never retired — measured 0 releases across 60 flushes, with everything behind it dropped at maxQueueSize. It now releases at the intended bound: in a host awaiting flush() ten times a second against a 300s window, the head batch releases at 2,100,000 ms (8 x the capped window), the same figure the earlier gated revision produced.

Each queue also clamps the remaining wait to MAX_RETRY_AFTER_MS when it reads the deadline back, and treats a clock that has moved behind the install point as ending the window rather than extending it by the size of the step. The deadline is wall clock, and parseRetryAfterMs applies the five-minute cap once, to the duration; without the clamp a backward step — NTP, a resumed VM, a user changing the device date — stretched a 60s wait to over an hour. Verified: a one-hour backward step returned 3660s from _retryAfterRemainingMs().

Why explicit flush still sends

An earlier revision of this PR gated PostHogTraces.flush() on the window. That was wrong, and the review that followed caught it:

  • posthog.flush() is what the serverless waitUntil keep-alive awaits. Gated, it resolved immediately with spans still queued, and the only recovery was a timer that safeSetTimeout unrefs — so a frozen isolate never ran it. Verified: after the window opened, two further flush() calls sent nothing and the queue stayed non-empty, even though the origin had recovered 5s in.
  • The traces spec's Flush triggers requirement says the global flush() SHALL drain the span queue, which the gate violated.

So the wait is honoured where it belongs — the periodic timer — and the damage it was meant to prevent is addressed at the source, by not charging the retry budget. An explicit flush inside a window costs one request; it no longer costs the spans.

The budget now counts backoff windows rather than attempts, which is the general form of that exemption. A refusal is charged only once per _nextFlushDelay() — the wait the timer would have taken — whoever drove the attempt. Gating on Retry-After alone left the same hole open whenever the endpoint named no wait, which is every refusal PostHog's capture path produces today: eight flush() calls retired a head batch in zero elapsed time, so a blip the timer would have ridden out cost the spans instead of a request. The traces spec's Error handling and retries requirement is explicit that an SDK exempting a caller-driven flush from the wait "SHALL NOT charge the resulting refusal against the batch's retry budget".

The window is read from clockNow() — monotonic where the platform has one — so an NTP correction or a resumed VM cannot hold the budget open, and it resets with the head batch rather than with the queue. Behaviour on the timer path is unchanged: eight refusals spread across the backoff, as before. This is traces-only; logs has no per-batch budget and metrics has no retry state at all, so neither can spend one early.

To be precise about what is and is not honoured, the exemption is not limited to teardown. Any caller-driven flush sends inside the window, including posthog-node's own automatic waitUntil debounce (_onSpanQueuedscheduleDebouncedFlush, 50 ms) and React Native's AppState listener, which takes the plain flush() on active and inactive — only background uses flushWithTimeout. Measured on the node waitUntil path: 200 span-ends over 20 s produce 200 exports, all inside a 300 s window. That is down from 266 on the base branch, and the spans are no longer dropped, but it is not zero. Suppressing those sends is exactly what the earlier revision did, and it stranded spans in a frozen isolate.

Request body limit

A payload over the limit is reported as too-large without a request, so the caller's existing halving loop isolates and drops the one oversized record without spending a request on every attempt.

This is @jonmcwest's ask from the #4579 review, where he measured a span carrying one multi-MB attribute being uploaded up to 11 times before the halving loop isolates it, 35–47 POSTs to drain a full 512-span queue around it, and ~480 healthy batches for the sticky shrink to ramp back up.

Worth flagging to him directly: those numbers were simulated against the 2 MB cap named in the traces-defaults comment he cited, and that comment was wrong — the deployed limit is 10 MiB. Against the real limit a 3 MB span is simply accepted, so the trigger is a larger record than his repro used. The saving itself is unchanged in size (see the table below); only the threshold moves.

  • Measured before compression, because the endpoint decompresses before it measures: RequestDecompressionLayer is layered outside DefaultBodyLimit::max(max_request_body_size_bytes), so a payload that gzips small is still refused on its decompressed size.
  • Measured in bytes, not UTF-16 code units — via a byteLengthOf helper extracted from the Buffer/TextEncoder block already in fetchWithRetry — so a CJK or emoji-heavy payload is measured the same way the server measures it.

The constant is set to 10 MiB, the largest limit any known deployment configures — what the ingestion service runs with — rather than the 2 MB it falls back to when nothing configures it. @dustinbyrne and @ioannisj both caught this: an earlier revision used the fallback, which is 5× below what capture actually accepts.

That direction matters, because the two errors are not symmetric. A ceiling set too high costs one wasted request, and the 413 path catches it. A ceiling set too low costs data, with no 413 to show for it. Measured against a 10 MiB endpoint on the earlier 2 MB constant:

at 2 MB at 10 MiB
logs, one 3 MiB record + one small 1 of 2 records delivered, 1 dropped 2 of 2 delivered
metrics, 25k series (~9.3 MiB) whole window dropped, 0 requests delivered in 1 request

Metrics is the worst of the three: it has no shrink path, so a refusal discards the entire window with one warn.

The saving the check exists for is unchanged at the higher number — measured with one 12 MiB record among healthy ones:

HTTP requests uploaded
logs, no check 16 72.0 MiB
logs, 10 MiB check 10 0.0 MiB
traces, no check 42 120.3 MiB
traces, 10 MiB check 32 0.1 MiB

The constant is still not authoritative — a proxy in front can lower the limit, and a self-hosted deployment runs the 2 MB fallback — so the 413 path stays the primary mechanism and handles every deployment configured below this ceiling. It is deliberately not configurable: it is internal, so it can be made configurable later without a breaking change, whereas shipping the option now would be permanent.

This departs from the traces spec as written. Batch assembly and concurrency names "the reactive 413 path (not proactive byte measurement) as the overflow mechanism" — wording that predates the review request above. PostHog/sdk-specs#58 amends it to permit a pre-send measurement that matches how the endpoint measures (uncompressed, in bytes, feeding the same shrink-and-drop path a 413 does) while keeping the 413 path mandatory.

Reviewer notes

  • The logs retry ceiling moved from 64x the flush interval to 30s, in 3279b97c, because that is what the logs contract states (openspec/specs/logs/spec.md: "exponential backoff capped at ~30s, floored by Retry-After when present"). It is interval-relative, so the size of the change depends on the host: 192s to 30s on web (3s interval), 640s to 30s on React Native (10s). Measured against a permanently-refusing endpoint, that is 24 to 123 requests/hour on web and 11 to 121 on React Native, with no change to what is delivered. Now carries its own changeset.
  • The browser gets that ceiling without the floor, and cannot have the floor yet. Retry-After is not a CORS-safelisted response header, so a cross-origin ingestion response has to send Access-Control-Expose-Headers: Retry-After before any browser can read it. Verified in Chromium against a two-origin harness: without that header both fetch's response.headers.get('retry-after') and XHR's getResponseHeader('retry-after') return null on a 429 whose status is plainly visible; adding it makes both return 120. So threading headers through RequestResponse would be inert until the ingestion service exposes the header, which is why that work stays out of this PR rather than being a small omission from it. For comparison, the browser's own event retry queue caps at 30 minutes (packages/browser/src/retry-queue.ts), so logs is now the more aggressive of the two during an outage.
  • The likely source of a 429 is not PostHog. With quota enforcement at capture abandoned, the header realistically arrives from a proxy, CDN or load balancer in front of capture — which is also why the cap exists.
  • The floor rule is not unspecified — the two specs contradict each other. logs reads as replacement ("honoring Retry-After when present and otherwise exponential backoff capped at ~30s"); traces reads as additive. Five of the six PostHog SDKs floor (rs, python, go, ios, this one); posthog-android replaces. Floor is the only rule that satisfies both spec sentences at once.
  • The five-minute cap is the least-validated number here. Three SDKs apply no cap at all; the two that do (rs, python) share a rule rather than a value — clamp to the ceiling already configured for the SDK's own backoff, 30s in both. This PR uses one 5-minute constant instead, because posthog-js's three queues have three different ceilings (~30s traces, ~64× the flush interval for logs, none for metrics) and cannot express that rule as a single number. Happy to be argued down; it is an internal constant with no public surface, so it is cheap to change later.
  • Both are proposed as spec clarifications in PostHog/sdk-specs#58, which also carries the 413-vs-proactive-measurement amendment below.
  • A sustained Retry-After lengthens how long traces holds a failing head batch. The per-batch budget is 8 backoff windows, and Retry-After floors the window, so a 5-minute header turns a ~2.5-minute hold into a ~35-minute one. Measured over 40 minutes of steady traffic against a permanently-refusing endpoint, span loss is identical either way (2200 of 2400 in both cases, since maxQueueSize bounds the queue regardless); the change is 127 send attempts down to 10. Deliberately left as is — the alternative, dropping on a wall-clock budget, discards spans the endpoint asked us to hold.
  • No @posthog/types change, and no new public surface. The outcome types live in core. parseRetryAfterMs and the RetryAfterWindow that holds the deadline both live in utils/retry-after.ts, which is deliberately outside the utils barrel — that barrel is re-exported wholesale from the package entry point. Verified unreachable from @posthog/core: neither symbol appears in the generated packages/{node,react-native}/references/*-latest.json. The only public delta is the optional retryAfterMs?: number on the three already-exported Send*BatchOutcome unions.

Verification

packages/core/src/__tests__/posthog.otlp-retry-after.spec.ts drives it end to end from a mocked 429 through to each of the three queues' outcomes, because a unit test of the parser alone would still pass with the plumbing missing. It also covers a response with no header, a transport whose headers.get throws, and the request count at the shipped fetchRetryCount default.

Per-queue tests cover the behaviour that matters rather than the field assignment: a Retry-After longer than the 30s exponential cap actually delays the retry; a shorter one does not shorten it; a capture or span end landing mid-flush cannot pull the retry back inside the window; a steady stream of captures does not push the flush timer out indefinitely; the logs size trigger and onReconnect do not send inside the window; and a non-retriable outcome ends the wait.

Every behavioural test was mutation-checked: reverting logs/index.ts, metrics/index.ts, traces/index.ts or posthog-core-stateless.ts fails exactly those tests and nothing else.

suite result
packages/core 1404 passed, 2 skipped (65 suites)
packages/node 1016 passed (36 suites)
packages/react-native 686 passed (43 suites)
packages/browser 5975 passed, 8 skipped (137 suites)

Every fix above was mutation-checked: reverting it to the shipped behaviour fails exactly the test written for it and nothing else. That includes the body-limit boundary, which pins both directions — a body of exactly the limit is sent, one byte more is not — because > drifting to >= would have refused an acceptable batch without a request and, in traces, halved it down and dropped the span with no 413 to show for it. A separate case pins the range between the service's fallback and its configured limit: reverting the constant to 2 MB fails exactly those three tests, one per signal.

Also exercised on an Android emulator, with the React Native example built from this branch against a mock ingestion endpoint. Answering 429 + Retry-After: 30, the log exports retried at +30.08s and +30.05s rather than on the SDK's 10s flush interval, and resumed on the next attempt once the mock returned 200.

Lint and format clean.

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

@posthog/core is bumped (patch); it has no checkbox above.

posthog-js (web) is deliberately unticked. The browser SDK does not use core's _sendOtlpBatch: posthog-logs.ts and posthog-metrics.ts build their outcomes from _send_request's callback, and RequestResponse (statusCode / text / json / error) carries no headers. So it never populates retryAfterMs, both new gates are inert there, and the pre-send size check never runs. One change does reach the browser, though: the browser SDK does use core's PostHogLogs / PostHogMetrics (it only supplies its own _sendLogsBatch / _sendMetricsBatch), and the post-flush re-arm changed from "leave a pending timer alone" to "keep whichever deadline is later". Under consecutive failures a capture-armed short timer no longer wins, so the retry follows the backoff. That is the intended "backoff is a floor" rule, and it is why the web bundle deltas are non-zero rather than only the mangled-names cache. Wiring it up means threading headers (or a parsed retryAfterMs) through RequestResponse and both the XHR and fetch paths, which is a separate change and deliberately not in this PR.

Checklist

  • 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

retryAfterMs is optional on types that were already exported, so implementors and consumers are unaffected. Behaviour only changes when the endpoint sends a header it does not send today, or when a batch exceeds a limit that would have refused it anyway.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Built with Claude Code, directed by @turnipdabeets. Came out of reviewing #4579 against the sdk-specs traces contract, which surfaced Retry-After as an unmet requirement shared by all three OTLP pipelines rather than anything #4579 introduced.

Decisions worth flagging, beyond those above:

  • Parsed once in the shared sender rather than per queue. The three queues had already drifted in retry shape (logs and traces have exponential backoff, metrics only re-arms a timer); putting the parse behind _sendOtlpBatch means one implementation of the wire format and one place to fix it.
  • Rejected: reading the header inside each queue. It would have required each to know about PostHogFetchHttpError, which the tagged-outcome design exists to avoid.
  • Two timer-arming paths per queue, not one. An earlier revision made _armFlushTimer keep whichever deadline was later. Since every capture arms the timer, that pushed the deadline out on each one and the flush never fired under a steady stream. The enqueue path now leaves a pending timer alone; only the flush-settle path extends it.
  • Rejected: making the body limit configurable. A new public option is a one-way door under a no-breaking-changes policy, and the case that needs it (a deployment configuring MAX_REQUEST_BODY_SIZE_BYTES above 10 MiB) is narrow. The constant is internal, so this stays reversible.

The branch was reviewed by a second Claude Code agent against sdk-specs before this description was written; each of its findings was independently reproduced with an executed failing test before being acted on.

https://claude.ai/code/session_01Qp8JHHcGSf7mocdZtHDR29

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Size Change: +42 kB (+0.2%)

Total Size: 20.8 MB

📦 View Changed
Filename Size Change
packages/browser/dist/array.full.es5.js 501 kB +2.19 kB (+0.44%)
packages/browser/dist/array.full.js 618 kB +1.44 kB (+0.23%)
packages/browser/dist/array.full.no-********.js 678 kB +1.93 kB (+0.29%)
packages/browser/dist/array.js 290 kB +1.44 kB (+0.5%)
packages/browser/dist/array.no-********.js 331 kB +1.93 kB (+0.59%)
packages/browser/dist/default-extensions.js 288 kB +1.44 kB (+0.5%)
packages/browser/dist/extension-bundles.js 159 kB +1.39 kB (+0.88%)
packages/browser/dist/main.js 295 kB +1.44 kB (+0.49%)
packages/browser/dist/module.full.js 622 kB +1.44 kB (+0.23%)
packages/browser/dist/module.full.no-********.js 682 kB +1.93 kB (+0.28%)
packages/browser/dist/module.js 294 kB +1.44 kB (+0.49%)
packages/browser/dist/module.mjs 294 kB +1.44 kB (+0.49%)
packages/browser/dist/module.no-********.js 335 kB +1.93 kB (+0.58%)
packages/browser/dist/module.slim.js 146 kB +4 B (0%)
packages/core/dist/logs/index.js 11.8 kB +910 B (+8.32%) 🔍
packages/core/dist/logs/index.mjs 9.83 kB +662 B (+7.22%) 🔍
packages/core/dist/metrics/index.js 15.7 kB +1.14 kB (+7.86%) 🔍
packages/core/dist/metrics/index.mjs 12.9 kB +922 B (+7.71%) 🔍
packages/core/dist/posthog-core-stateless.js 48.7 kB +1.33 kB (+2.82%)
packages/core/dist/posthog-core-stateless.mjs 45.3 kB +1.28 kB (+2.92%)
packages/core/dist/traces/index.js 26.4 kB +1.54 kB (+6.18%) 🔍
packages/core/dist/traces/index.mjs 23.8 kB +1.24 kB (+5.48%) 🔍
packages/core/dist/utils/backoff.js 2.36 kB +2.36 kB (new file) 🆕
packages/core/dist/utils/backoff.mjs 611 B +611 B (new file) 🆕
packages/core/dist/utils/flush-timer.js 2.06 kB +2.06 kB (new file) 🆕
packages/core/dist/utils/flush-timer.mjs 725 B +725 B (new file) 🆕
packages/core/dist/utils/retry-after.js 3.38 kB +3.38 kB (new file) 🆕
packages/core/dist/utils/retry-after.mjs 1.84 kB +1.84 kB (new file) 🆕
packages/node/dist/client.js 62.2 kB +286 B (+0.46%)
packages/node/dist/client.mjs 58.6 kB +286 B (+0.49%)
ℹ️ View Unchanged
Filename Size
packages/ai/dist/adk/index.cjs 35.6 kB
packages/ai/dist/adk/index.mjs 35.4 kB
packages/ai/dist/anthropic/index.cjs 35.9 kB
packages/ai/dist/anthropic/index.mjs 34.5 kB
packages/ai/dist/gemini/index.cjs 33.5 kB
packages/ai/dist/gemini/index.mjs 33.3 kB
packages/ai/dist/index.cjs 50.2 kB
packages/ai/dist/index.mjs 50 kB
packages/ai/dist/langchain/index.cjs 36.7 kB
packages/ai/dist/langchain/index.mjs 36.6 kB
packages/ai/dist/langchain/middleware/index.cjs 42.8 kB
packages/ai/dist/langchain/middleware/index.mjs 42.5 kB
packages/ai/dist/openai-agents/index.cjs 29.5 kB
packages/ai/dist/openai-agents/index.mjs 29.4 kB
packages/ai/dist/openai/index.cjs 78.8 kB
packages/ai/dist/openai/index.mjs 78.2 kB
packages/ai/dist/otel/index.cjs 15.4 kB
packages/ai/dist/otel/index.mjs 15.2 kB
packages/ai/dist/vercel/index.cjs 40.9 kB
packages/ai/dist/vercel/index.mjs 40.8 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 216 B
packages/browser-common/dist/constants.js 1.75 kB
packages/browser-common/dist/constants.mjs 219 B
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.js 585 B
packages/browser-common/dist/extension.mjs 12 B
packages/browser-common/dist/index.js 2.98 kB
packages/browser-common/dist/index.mjs 130 B
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/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/index.js 3.68 kB
packages/browser-common/dist/types/index.mjs 144 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 4.61 kB
packages/browser-common/dist/types/surveys.mjs 2.17 kB
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 24.6 kB
packages/browser-common/dist/utils/autocapture-utils.mjs 18.6 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/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.2 kB
packages/browser-common/dist/utils/general-utils.js 7.91 kB
packages/browser-common/dist/utils/general-utils.mjs 4.86 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.5 kB
packages/browser-common/dist/utils/logger.mjs 1.61 kB
packages/browser-common/dist/utils/matcher-utils.js 2.94 kB
packages/browser-common/dist/utils/matcher-utils.mjs 1.33 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-utils.js 7.17 kB
packages/browser-common/dist/utils/request-utils.mjs 4.49 kB
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/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.45 kB
packages/browser-common/dist/utils/url-targeting-utils.mjs 863 B
packages/browser-common/dist/utils/uuidv7.js 6.98 kB
packages/browser-common/dist/utils/uuidv7.mjs 5.37 kB
packages/browser-next/dist/analytics-********.js 1.68 kB
packages/browser-next/dist/analytics-********.mjs 219 B
packages/browser-next/dist/analytics-options.js 585 B
packages/browser-next/dist/analytics-options.mjs 12 B
packages/browser-next/dist/analytics.js 6.62 kB
packages/browser-next/dist/analytics.mjs 5.15 kB
packages/browser-next/dist/bot-filter.js 2.38 kB
packages/browser-next/dist/bot-filter.mjs 1.09 kB
packages/browser-next/dist/capture-v1.js 27.8 kB
packages/browser-next/dist/capture-v1.mjs 25.3 kB
packages/browser-next/dist/core.js 1.69 kB
packages/browser-next/dist/core.mjs 185 B
packages/browser-next/dist/extensions/registry.js 3.41 kB
packages/browser-next/dist/extensions/registry.mjs 2.11 kB
packages/browser-next/dist/id.js 2.25 kB
packages/browser-next/dist/id.mjs 983 B
packages/browser-next/dist/index.js 2.68 kB
packages/browser-next/dist/index.mjs 1.18 kB
packages/browser-next/dist/lane.js 18.1 kB
packages/browser-next/dist/lane.mjs 16.9 kB
packages/browser-next/dist/logger.js 1.87 kB
packages/browser-next/dist/logger.mjs 581 B
packages/browser-next/dist/posthog.js 33.2 kB
packages/browser-next/dist/posthog.mjs 30.9 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/request.js 4.61 kB
packages/browser-next/dist/request.mjs 3.21 kB
packages/browser-next/dist/state.js 24.9 kB
packages/browser-next/dist/state.mjs 23.2 kB
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 366 kB
packages/browser/dist/conversations.js 69 kB
packages/browser/dist/crisp-chat-integration.js 2 kB
packages/browser/dist/customizations.full.js 18.1 kB
packages/browser/dist/customizations.js 17.7 kB
packages/browser/dist/dead-clicks-autocapture.js 18.4 kB
packages/browser/dist/element-inference.js 5.62 kB
packages/browser/dist/exception-autocapture.js 13.7 kB
packages/browser/dist/external-scripts-loader.js 3.55 kB
packages/browser/dist/intercom-integration.js 2.05 kB
packages/browser/dist/lazy-********.js 208 kB
packages/browser/dist/logs.js 5.83 kB
packages/browser/dist/module.slim.no-********.js 161 kB
packages/browser/dist/posthog-********.js 208 kB
packages/browser/dist/product-tours-preview.js 80.8 kB
packages/browser/dist/product-tours.js 122 kB
packages/browser/dist/recorder-v2.js 130 kB
packages/browser/dist/recorder.js 130 kB
packages/browser/dist/rrweb-plugin-console-record.js 7.83 kB
packages/browser/dist/rrweb-types.js 2.41 kB
packages/browser/dist/rrweb.js 322 kB
packages/browser/dist/surveys-preview.js 79.5 kB
packages/browser/dist/surveys.js 100 kB
packages/browser/dist/tracing-headers.js 3.74 kB
packages/browser/dist/web-vitals-soft-navs.js 9.87 kB
packages/browser/dist/web-vitals-with-attribution-soft-navs.js 25.4 kB
packages/browser/dist/web-vitals-with-attribution.js 25.3 kB
packages/browser/dist/web-vitals.js 9.85 kB
packages/browser/react/dist/esm/index.js 22.1 kB
packages/browser/react/dist/esm/slim/index.js 18.5 kB
packages/browser/react/dist/esm/surveys/index.js 3.61 kB
packages/browser/react/dist/umd/index.js 26.4 kB
packages/browser/react/dist/umd/slim/index.js 22.3 kB
packages/browser/react/dist/umd/surveys/index.js 5.63 kB
packages/convex/dist/client/feature-flags/crypto.js 76 B
packages/convex/dist/client/feature-flags/evaluator.js 14.9 kB
packages/convex/dist/client/feature-flags/index.js 196 B
packages/convex/dist/client/feature-flags/match-********.js 5.08 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.8 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 2.64 kB
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 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.23 kB
packages/core/dist/error-tracking/coercers/error-coercer.mjs 888 B
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 5.66 kB
packages/core/dist/error-tracking/error-properties-builder.mjs 4.23 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.11 kB
packages/core/dist/error-tracking/parsers/base.mjs 640 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 4.85 kB
packages/core/dist/error-tracking/parsers/index.mjs 2.01 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.52 kB
packages/core/dist/error-tracking/release.mjs 203 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 22.2 kB
packages/core/dist/featureFlagLocalEvaluation.mjs 19.6 kB
packages/core/dist/featureFlagUtils.js 8.59 kB
packages/core/dist/featureFlagUtils.mjs 5.49 kB
packages/core/dist/gzip.js 5.88 kB
packages/core/dist/gzip.mjs 3.87 kB
packages/core/dist/index.js 25 kB
packages/core/dist/index.mjs 1.93 kB
packages/core/dist/logs/logs-utils.js 6.69 kB
packages/core/dist/logs/logs-utils.mjs 4.51 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/metrics-utils.js 3.75 kB
packages/core/dist/metrics/metrics-utils.mjs 1.71 kB
packages/core/dist/metrics/types.js 585 B
packages/core/dist/metrics/types.mjs 12 B
packages/core/dist/posthog-core.js 49.6 kB
packages/core/dist/posthog-core.mjs 43.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 4.36 kB
packages/core/dist/surveys/events.mjs 2.05 kB
packages/core/dist/surveys/index.js 6.64 kB
packages/core/dist/surveys/index.mjs 798 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.78 kB
packages/core/dist/surveys/property-********.mjs 2.14 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.33 kB
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.82 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/otlp.js 6.33 kB
packages/core/dist/traces/otlp.mjs 4.11 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 19.6 kB
packages/core/dist/traces/span.mjs 16.4 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.39 kB
packages/core/dist/types.mjs 5.23 kB
packages/core/dist/utils/bot-detection.js 3.38 kB
packages/core/dist/utils/bot-detection.mjs 1.96 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/index.js 16.4 kB
packages/core/dist/utils/index.mjs 3.38 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 2.97 kB
packages/core/dist/utils/otlp-********.mjs 1.32 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.04 kB
packages/mcp/dist/extensions/capture.mjs 2.58 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 5.53 kB
packages/mcp/dist/extensions/constants.mjs 3.03 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 459 B
packages/mcp/dist/extensions/exceptions.js 2.67 kB
packages/mcp/dist/extensions/exceptions.mjs 1.19 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 5.02 kB
packages/mcp/dist/extensions/instrument-********.mjs 3.18 kB
packages/mcp/dist/extensions/instrument-highlevel.js 12.8 kB
packages/mcp/dist/extensions/instrument-highlevel.mjs 10.2 kB
packages/mcp/dist/extensions/instrumentation.js 27.9 kB
packages/mcp/dist/extensions/instrumentation.mjs 21.9 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 7.63 kB
packages/mcp/dist/extensions/internal.mjs 5.23 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 7.66 kB
packages/mcp/dist/extensions/mcp-********.mjs 6.09 kB
packages/mcp/dist/extensions/mcp-sdk-compat.js 5.13 kB
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 2.9 kB
packages/mcp/dist/extensions/model-parameters.js 3.7 kB
packages/mcp/dist/extensions/model-parameters.mjs 1.53 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 11.8 kB
packages/mcp/dist/extensions/posthog-events.mjs 7.98 kB
packages/mcp/dist/extensions/posthog-mcp.js 9.69 kB
packages/mcp/dist/extensions/posthog-mcp.mjs 7.12 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.78 kB
packages/mcp/dist/extensions/sanitization.mjs 2.98 kB
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.74 kB
packages/mcp/dist/extensions/session.mjs 4.12 kB
packages/mcp/dist/extensions/sink.js 4.47 kB
packages/mcp/dist/extensions/sink.mjs 2.67 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.6 kB
packages/mcp/dist/extensions/truncation.mjs 9.79 kB
packages/mcp/dist/index.js 8.88 kB
packages/mcp/dist/index.mjs 4.76 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/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 305 B
packages/next/dist/server/createPostHog.js 1.44 kB
packages/next/dist/server/getPostHog.js 3.45 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 10.6 kB
packages/nextjs-config/dist/config.mjs 8.96 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 4.91 kB
packages/nextjs-config/dist/strip-sourcemap-********.mjs 2.96 kB
packages/nextjs-config/dist/utils.js 3.93 kB
packages/nextjs-config/dist/utils.mjs 1.72 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/experimental.js 852 B
packages/node/dist/experimental.mjs 279 B
packages/node/dist/exports.js 6.3 kB
packages/node/dist/exports.mjs 388 B
packages/node/dist/extensions/context/context.js 2.22 kB
packages/node/dist/extensions/context/context.mjs 863 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.48 kB
packages/node/dist/extensions/error-tracking/index.mjs 3.17 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/express.js 5.07 kB
packages/node/dist/extensions/express.mjs 2.78 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 32.3 kB
packages/node/dist/extensions/feature-flags/feature-flags.mjs 29.8 kB
packages/node/dist/extensions/nestjs.js 5.71 kB
packages/node/dist/extensions/nestjs.mjs 3.42 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 3.41 kB
packages/node/dist/extensions/tracing-headers.mjs 1.53 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.22 kB
packages/node/dist/feature-flag-evaluations.mjs 4.77 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.52 kB
packages/node/dist/types.mjs 224 B
packages/node/dist/version.js 1.31 kB
packages/node/dist/version.mjs 46 B
packages/nuxt/dist/module.mjs 6.13 kB
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 698 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 480 B
packages/nuxt/dist/runtime/nitro-plugin-v3.js 574 B
packages/nuxt/dist/runtime/nitro-plugin.js 1.03 kB
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.42 kB
packages/openfeature-node-provider/dist/mapping.mjs 3.21 kB
packages/openfeature-node-provider/dist/provider.js 4.09 kB
packages/openfeature-node-provider/dist/provider.mjs 2.6 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.31 kB
packages/react-native/dist/error-tracking/index.js 9.97 kB
packages/react-native/dist/error-tracking/utils.js 2.58 kB
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB
packages/react-native/dist/hooks/useFeatureFlag.js 1.86 kB
packages/react-native/dist/hooks/useFeatureFlagResult.js 983 B
packages/react-native/dist/hooks/useFeatureFlags.js 941 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.45 kB
packages/react-native/dist/hooks/usePostHog.js 544 B
packages/react-native/dist/hooks/utils.js 988 B
packages/react-native/dist/index.js 4.33 kB
packages/react-native/dist/logs-********.js 3.66 kB
packages/react-native/dist/native-deps.js 8.73 kB
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B
packages/react-native/dist/optional/OptionalPlugin.js 1.06 kB
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 872 B
packages/react-native/dist/posthog-rn.js 67.5 kB
packages/react-native/dist/PostHogContext.js 329 B
packages/react-native/dist/PostHogErrorBoundary.js 3.19 kB
packages/react-native/dist/PostHogMaskView.js 1.68 kB
packages/react-native/dist/PostHogProvider.js 6 kB
packages/react-native/dist/storage.js 5.76 kB
packages/react-native/dist/surveys/components/BottomSection.js 1.51 kB
packages/react-native/dist/surveys/components/Cancel.js 1.1 kB
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.76 kB
packages/react-native/dist/surveys/components/IntroMessage.js 1.65 kB
packages/react-native/dist/surveys/components/QuestionHeader.js 1.47 kB
packages/react-native/dist/surveys/components/QuestionTypes.js 14.2 kB
packages/react-native/dist/surveys/components/SurveyModal.js 7.24 kB
packages/react-native/dist/surveys/components/Surveys.js 7.27 kB
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 2.69 kB
packages/react-native/dist/surveys/icons.js 10 kB
packages/react-native/dist/surveys/index.js 600 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 7.37 kB
packages/react-native/dist/surveys/safeStyleSheet.js 448 B
packages/react-native/dist/surveys/survey-shuffling.js 2.95 kB
packages/react-native/dist/surveys/survey-translations.js 1.17 kB
packages/react-native/dist/surveys/surveys-utils.js 11.5 kB
packages/react-native/dist/surveys/useActivatedSurveys.js 3.68 kB
packages/react-native/dist/surveys/useSurveyStorage.js 2.48 kB
packages/react-native/dist/tooling/expoconfig.js 23.8 kB
packages/react-native/dist/tooling/metroconfig.js 2.32 kB
packages/react-native/dist/tooling/posthogMetroSerializer.js 7.45 kB
packages/react-native/dist/tooling/utils.js 4.46 kB
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 70 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 237 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.57 kB
packages/react-native/dist/types.js 70 B
packages/react-native/dist/utils.js 1.3 kB
packages/react-native/dist/version.js 130 B
packages/react/dist/esm/index.js 22.1 kB
packages/react/dist/esm/slim/index.js 18.5 kB
packages/react/dist/esm/surveys/index.js 3.61 kB
packages/react/dist/umd/index.js 26.4 kB
packages/react/dist/umd/slim/index.js 22.3 kB
packages/react/dist/umd/surveys/index.js 5.63 kB
packages/rollup-plugin/dist/index.js 10.2 kB
packages/rrweb/all/dist/rrweb-all.cjs 645 kB
packages/rrweb/all/dist/rrweb-all.js 644 kB
packages/rrweb/all/dist/rrweb-all.umd.cjs 676 kB
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 334 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.2 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 17.1 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 16.4 kB
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 8.75 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 6.85 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 6.75 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 7.14 kB
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 3.77 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 220 kB
packages/rrweb/record/dist/rrweb-record.js 220 kB
packages/rrweb/record/dist/rrweb-record.umd.cjs 224 kB
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 110 kB
packages/rrweb/replay/dist/rrweb-replay.cjs 429 kB
packages/rrweb/replay/dist/rrweb-replay.js 429 kB
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 453 kB
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 225 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 142 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 142 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 155 kB
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 76.1 kB
packages/rrweb/rrdom/dist/rrdom.cjs 167 kB
packages/rrweb/rrdom/dist/rrdom.js 167 kB
packages/rrweb/rrdom/dist/rrdom.umd.cjs 179 kB
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 86.9 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-********.js 132 kB
packages/rrweb/rrweb-snapshot/dist/rebuild-B8YF-X1O.cjs 133 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 93.7 kB
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 44 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 206 kB
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 90.7 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 248 kB
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.min.cjs 111 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-********.cjs 34.1 kB
packages/rrweb/rrweb-snapshot/dist/snapshot-********.js 32.2 kB
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 49.5 kB
packages/rrweb/rrweb-snapshot/dist/types-********.js 44.2 kB
packages/rrweb/rrweb/dist/rrweb.cjs 630 kB
packages/rrweb/rrweb/dist/rrweb.js 629 kB
packages/rrweb/rrweb/dist/rrweb.umd.cjs 658 kB
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 324 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 9.81 kB
packages/rrweb/utils/dist/rrweb-utils.js 9.3 kB
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 10.3 kB
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 4.97 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.55 kB
packages/types/dist/index.mjs 75 B
packages/types/dist/posthog-config.js 585 B
packages/types/dist/posthog-config.mjs 12 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 2.38 kB
packages/webpack-plugin/dist/config.mjs 1.31 kB
packages/webpack-plugin/dist/index.js 9.29 kB
packages/webpack-plugin/dist/index.mjs 5.51 kB
tooling/changelog/dist/index.js 3.31 kB
tooling/rollup-utils/dist/index.js 1.17 kB

compressed-size-action

@turnipdabeets
turnipdabeets force-pushed the fix/otlp-honor-retry-after branch from 68d9c61 to 197acec Compare September 1, 2026 16:45
…eues

Parses `Retry-After` once in the shared OTLP sender and applies it as a floor on
each export queue's own backoff, and refuses a batch over the endpoint's 2 MB
body limit without spending a request on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qp8JHHcGSf7mocdZtHDR29
@turnipdabeets
turnipdabeets force-pushed the fix/otlp-honor-retry-after branch from f7ee901 to 3db04a2 Compare September 1, 2026 21:41
@turnipdabeets turnipdabeets self-assigned this Sep 1, 2026
turnipdabeets and others added 8 commits September 2, 2026 10:21
…imer

The window was only consulted where a timer was armed, so an explicit
flush() — the lifecycle and per-request path — sent inside it. Traces
spent its whole per-batch retry budget there and dropped the spans
before the wait elapsed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vkNv2jdvWeE8hoAuiwgCr
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vkNv2jdvWeE8hoAuiwgCr
Gating traces flush() on the window stranded spans: it is what the
serverless waitUntil keep-alive awaits, and the recovery timer is
unref'd, so a frozen isolate never sent them. Protect the head batch's
retry budget instead of suppressing the send. The wall-clock deadline is
now clamped, so a backward clock step can't stretch a wait past the cap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vkNv2jdvWeE8hoAuiwgCr
The deadline was re-installed by the very refusal it excused, so a host
flushing faster than the window kept it open forever: the traces retry
budget never advanced, the head batch never retired, and everything
behind it was dropped at maxQueueSize. Measured 0 releases over 60
flushes; now releases at the intended 8 x window. A backward clock step
no longer holds a window open either, and MAX_RETRY_AFTER_MS is out of
the public barrel.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vkNv2jdvWeE8hoAuiwgCr
…three copies

Share one RetryAfterWindow across the logs, metrics and traces queues, move
parseRetryAfterMs off the package entry point, and stop a header-less refusal,
a size verdict or a clock step from discarding an open window.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017SWWFUdrPWaHTpwFNr4DgC
turnipdabeets and others added 2 commits September 3, 2026 14:41
…s queue

Metrics never retired its pending timer when a flush started, so a wait armed
from a Retry-After outlived the window a later successful flush had already
closed, holding every subsequent capture for up to five minutes. Logs had the
mirror gap: a capture landing mid-flush armed a plain-interval timer before the
window existed, and only the background wrapper re-armed it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017SWWFUdrPWaHTpwFNr4DgC
…loses

The re-arm helpers only ever move a timer later, so a record or series captured
while a send was in flight stayed pinned to the window that send then closed —
up to five minutes for a wait already over. Re-arm outright instead, and let
onReconnect arm a timer during a window rather than returning with nothing
scheduled, which stranded logs after an explicit flush was refused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017SWWFUdrPWaHTpwFNr4DgC
@turnipdabeets
turnipdabeets marked this pull request as ready for review September 3, 2026 19:28
@turnipdabeets
turnipdabeets requested a review from a team as a code owner September 3, 2026 19:29
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
.changeset/otlp-honor-retry-after.md:2-4
**Browser release metadata omitted**

These changesets omit `posthog-js`, even though the shared timer changes affect the browser package and add browser mangling metadata. This leaves the changed browser behavior without the required patch-version entry and changelog metadata; please add `posthog-js` to the applicable changeset metadata, including the sibling changeset where appropriate.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(core): release a queue once the Retr..." | Re-trigger Greptile

Comment thread .changeset/otlp-honor-retry-after.md
turnipdabeets and others added 2 commits September 3, 2026 15:37
An explicit flush() skips the wait but was charging the refusal, so a host
draining per request retired a batch in eight calls and no elapsed time.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L8eFZB35NExUZyq5hGgh43
The shared timer change reaches the browser even though the window never opens
there, so it needs its own changeset line. Comments that narrated the bugs
behind each fix are cut back to the constraint a reader needs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017SWWFUdrPWaHTpwFNr4DgC
Comment thread packages/core/src/posthog-core-stateless.ts Outdated
Comment thread packages/core/src/utils/retry-after.ts Outdated
Comment thread .changeset/otlp-honor-retry-after.md Outdated
@dustinbyrne
dustinbyrne requested a review from a team September 4, 2026 04:25
Comment thread packages/core/src/metrics/index.ts Outdated
Comment thread packages/core/src/utils/retry-after.ts Outdated
@ioannisj

ioannisj commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Worth checking this comment as well #4726 (comment). Do we need it or should we just stay reactive to 413 path. I think it's also lower than the accepted max

turnipdabeets and others added 2 commits September 4, 2026 12:00
…fallback

The ceiling was the 2 MB `MAX_REQUEST_BODY_SIZE_BYTES` falls back to, but the
ingestion service runs with 10 MiB, so bodies between the two were refused
without a request and their records dropped — a whole window, in metrics, which
has no shrink path. Raise it to the largest limit any known deployment
configures; the 413 path still covers the ones configured lower.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YE1TyDWGyLwUXEX3ffy83K
The parser rejects a zero delta as well as a negative one, and the window's
justification named a retry-budget effect that no longer applies to traces —
the rule holds for the logs and metrics gates instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YE1TyDWGyLwUXEX3ffy83K
turnipdabeets and others added 3 commits September 4, 2026 17:05
…licated aside

The test builds a circular payload, not one past the max string length, and
the barrel note was the same paragraph in two files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBUa53f3QqECUyxnkSiWGA
Traces ships new in the same release through #4579, so naming it here reads
as a fix to behavior that never existed. Also drops the split-and-isolate
claim from the oversized entry: metrics drops the window rather than halving.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBUa53f3QqECUyxnkSiWGA
capture-logs caps the raw request body (main.rs DefaultBodyLimit) and the
gzip output (service.rs decompress_gzip_capped) at the same value, so the
comment was wrong to say the wire bytes are not capped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AAPCyRnC5HbukEZV9hbai
Comment thread packages/core/src/posthog-core-stateless.ts Outdated
@jonmcwest

jonmcwest commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Follow-up: background event flushes bypass the traces retry window.

Node's background event flush calls public flush(), which drains traces during Retry-After. Gate automatic traces drains on the window.

OTLP recommends honoring the header; OTel's ForceFlush contract does not specify a blanket exception. Any explicit-flush or serverless bypass should remain a documented lifecycle trade-off, not be presented as spec-required behavior. Non-blocking for the MVP.

Sources: Node flush path · OTLP throttling · OTel ForceFlush contract.

Agent-assisted review.

Comment thread packages/core/src/utils/retry-after.ts Outdated
Comment thread packages/core/src/traces/index.ts Outdated
Comment thread packages/core/src/logs/index.ts
Comment thread packages/core/src/logs/index.ts Outdated
@jonmcwest

jonmcwest commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Protocol deviation: the SDK retries more statuses than OTLP allows.

OTLP permits retries for 429, 502, 503, and 504, and forbids retrying other 4xx/5xx responses. The SDK additionally retries 408 and the remaining 5xx statuses.

This predates the PR and supports existing tests and the backend's transient 500 responses. Document it as a compatibility deviation, and coordinate server-side status changes before narrowing client retries. Non-blocking here does not mean OTLP-conformant.

Sources: SDK retry statuses · OTLP retry statuses · ingestion failure response.

Agent-assisted review.

turnipdabeets and others added 2 commits September 8, 2026 09:53
Request decompression runs outside the body limit, so a gzip request is only
measured once, after it is decoded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
turnipdabeets and others added 3 commits September 8, 2026 10:39
The pre-commit JSON formatter added a trailing newline the api-extractor
pipeline does not emit, so `Check public API references` saw a diff.
The events flush timer no longer drains spans while the traces queue is
honouring a Retry-After window. A batch the SDK measured as too large itself
now splits that drain only, leaving the batch size the next drain starts from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
@turnipdabeets

Copy link
Copy Markdown
Contributor Author

@jonmcwest — on background event flushes bypassing the retry window: done in 6ee946706. flushAutomatic() on PostHogCoreStateless is what flushBackground() now calls, defaulting to flush() so browser and react-native are unchanged; node overrides it to skip the span drain while the traces Retry-After window is open. Explicit flush() still drains, as documented.

turnipdabeets and others added 5 commits September 8, 2026 11:09
A refusal naming a longer wait now pushes the deadline out, bounded at five
minutes from where the window was installed. Logs, metrics and traces jitter
their own backoff, drawn once per failure, and metrics backs off exponentially
rather than retrying on a fixed interval.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
…state

Both capabilities document the retry delay as exponential backoff capped at
~30s. Only traces applied it, so a 5s interval reached 320s after six doublings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
…726-merge

# Conflicts:
#	packages/core/src/traces/config.ts
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjT26chjUzuPSyJZqh4AWQ
@turnipdabeets

Copy link
Copy Markdown
Contributor Author

@jonmcwest — on retrying more statuses than OTLP allows. Your reading of the code is right, but I do not think this is an undocumented deviation, so I have left it alone.

isPostHogFetchRetryableError is 408 || 429 || >= 500, and that is what our own contract requires. Both capabilities state it in the same words:

408/429/5xx/network error → retriable … other 4xx (notably 400 and 401) → non-retriable

openspec/specs/traces/spec.md:759 and openspec/specs/logs/spec.md:389. So the SDK conforms to the PostHog spec, and narrowing it to OTLP's 429/502/503/504 would move it out of spec rather than into it. The divergence from OTLP is a deliberate PostHog decision that is already written down, not drift.

The other reason to leave it: that predicate is the shared transport for analytics events, not just OTLP. This PR does not otherwise touch event delivery, and dropping >= 500 would stop retrying the transient 500s capture returns — data loss for every Node user, from a change in a PR about OTLP export queues.

So I read this as a question for the ingestion team and the spec rather than something to fix here: if we want OTLP's narrower set, the spec changes first and the client follows. Happy to open that if you think it is worth doing — but flagging that it trades conformance for delivery on a path that is working today.

turnipdabeets and others added 3 commits September 8, 2026 12:44
The cap landed in 3279b97 with no changelog entry, and it changes retry
cadence for posthog-js and posthog-react-native.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RWoFx4BctNmXnpnKS79Qgz
The oxfmt-data pre-commit hook appends a trailing newline to any staged
.json, which the api-extractor output does not carry, so committing these
through the hook fails the Check public API references job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RWoFx4BctNmXnpnKS79Qgz
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.

4 participants