@posthog/convex 2.0.27 → 2.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +27 -0
- package/README.md +5 -405
- package/dist/component/version.d.ts +1 -1
- package/dist/component/version.js +1 -1
- package/package.json +3 -3
- package/src/component/version.ts +1 -1
package/LICENSE
CHANGED
|
@@ -324,3 +324,30 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
324
324
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
325
325
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
326
326
|
SOFTWARE.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
Some files in this codebase contain code from MCPCat/mcpcat-typescript-sdk.
|
|
331
|
+
In such cases it is explicitly stated in the file header. This license only applies to the relevant code in such cases.
|
|
332
|
+
|
|
333
|
+
MIT License
|
|
334
|
+
|
|
335
|
+
Copyright (c) 2025 MCPcat
|
|
336
|
+
|
|
337
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
338
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
339
|
+
in the Software without restriction, including without limitation the rights
|
|
340
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
341
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
342
|
+
furnished to do so, subject to the following conditions:
|
|
343
|
+
|
|
344
|
+
The above copyright notice and this permission notice shall be included in all
|
|
345
|
+
copies or substantial portions of the Software.
|
|
346
|
+
|
|
347
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
348
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
349
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
350
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
351
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
352
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
353
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,414 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
<img alt="@posthog/convex" src="https://res.cloudinary.com/dmukukwp6/image/upload/q_auto,f_auto/posthog_convex_c017c269f8.png" width="500">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<h1 align="center">@posthog/convex</h1>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
PostHog analytics and feature flags for your Convex backend.
|
|
9
|
-
</p>
|
|
1
|
+
# PostHog Convex package
|
|
10
2
|
|
|
11
3
|
<p align="center">
|
|
12
4
|
<a href="https://www.npmjs.com/package/@posthog/convex"><img src="https://badge.fury.io/js/@posthog%2Fconvex.svg" alt="npm version"></a>
|
|
13
5
|
<a href="https://www.convex.dev/components/posthog/convex"><img src="https://www.convex.dev/components/badge/posthog/convex" alt="Convex Component"></a>
|
|
14
6
|
</p>
|
|
15
7
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
The official [PostHog](https://posthog.com) component for [Convex](https://convex.dev). Capture events, identify users, manage groups, and evaluate feature flags — all from your queries, mutations, and actions.
|
|
19
|
-
|
|
20
|
-
Found a bug? Feature request? [File it here](https://github.com/PostHog/posthog-js/issues).
|
|
21
|
-
|
|
22
|
-
## 🚀 Quick Start
|
|
23
|
-
|
|
24
|
-
Install the package (requires Convex 1.39 or newer):
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
pnpm add @posthog/convex
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Register the component in your `convex/convex.config.ts` and forward the env vars from your app to the component:
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
// convex/convex.config.ts
|
|
34
|
-
import { defineApp } from "convex/server";
|
|
35
|
-
import { v } from "convex/values";
|
|
36
|
-
import posthog from "@posthog/convex/convex.config.js";
|
|
37
|
-
|
|
38
|
-
const app = defineApp({
|
|
39
|
-
env: {
|
|
40
|
-
// Required. PostHog project token (`phc_…`) — used to send events and evaluate flags remotely.
|
|
41
|
-
POSTHOG_PROJECT_TOKEN: v.string(),
|
|
42
|
-
// Optional. PostHog host. Defaults to `https://us.i.posthog.com`; use `https://eu.i.posthog.com` for EU Cloud or your self-hosted URL.
|
|
43
|
-
POSTHOG_HOST: v.optional(v.string()),
|
|
44
|
-
// Optional. A feature flags secure API key (`phs_…`, recommended) or personal API key (`phx_…`). Setting it enables local feature flag evaluation.
|
|
45
|
-
POSTHOG_PERSONAL_API_KEY: v.optional(v.string()),
|
|
46
|
-
// Optional. Cron interval (seconds) for refreshing flag definitions. Defaults to 60. Raise it on free-tier dev deployments to reduce function-call usage.
|
|
47
|
-
POSTHOG_FLAGS_POLLING_INTERVAL_SECONDS: v.optional(v.string()),
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
app.use(posthog, {
|
|
52
|
-
env: {
|
|
53
|
-
POSTHOG_PROJECT_TOKEN: app.env.POSTHOG_PROJECT_TOKEN,
|
|
54
|
-
POSTHOG_HOST: app.env.POSTHOG_HOST,
|
|
55
|
-
POSTHOG_PERSONAL_API_KEY: app.env.POSTHOG_PERSONAL_API_KEY,
|
|
56
|
-
POSTHOG_FLAGS_POLLING_INTERVAL_SECONDS: app.env.POSTHOG_FLAGS_POLLING_INTERVAL_SECONDS,
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
export default app;
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Set your PostHog credentials on your Convex deployment:
|
|
64
|
-
|
|
65
|
-
```sh
|
|
66
|
-
npx convex env set POSTHOG_PROJECT_TOKEN phc_your_project_token
|
|
67
|
-
npx convex env set POSTHOG_HOST https://us.i.posthog.com
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
To enable local feature flag evaluation, also set a [feature flags secure API key](https://posthog.com/docs/feature-flags/local-evaluation#step-1-find-your-feature-flags-secure-api-key) (`phs_…`) with read access to feature flags:
|
|
71
|
-
|
|
72
|
-
```sh
|
|
73
|
-
npx convex env set POSTHOG_PERSONAL_API_KEY phs_your_feature_flags_secure_api_key
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
> Personal API keys (`phx_…`) also still work for local evaluation, but PostHog recommends the project-scoped feature flags secure API key going forward. Setting this env var is what flips on local evaluation — the component's built-in refresh cron starts populating flag definitions on the next tick, no redeploy needed.
|
|
77
|
-
|
|
78
|
-
Create a `convex/posthog.ts` file to initialize the client. Credentials live on the component, so this file is just for callbacks (identify, beforeSend):
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
// convex/posthog.ts
|
|
82
|
-
import { PostHog } from "@posthog/convex";
|
|
83
|
-
import { components } from "./_generated/api";
|
|
84
|
-
|
|
85
|
-
export const posthog = new PostHog(components.posthog);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
That's the whole setup — feature flag methods will start returning live values on the next cron tick. The component refreshes flag definitions once a minute by default when `POSTHOG_PERSONAL_API_KEY` is set. To tune the cadence (e.g. raise it to `300` for a free-tier dev deployment), set `POSTHOG_FLAGS_POLLING_INTERVAL_SECONDS` and redeploy:
|
|
89
|
-
|
|
90
|
-
```sh
|
|
91
|
-
npx convex env set POSTHOG_FLAGS_POLLING_INTERVAL_SECONDS 300
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
If you call a local-eval method (`getFeatureFlag`, `isFeatureEnabled`, …) without `POSTHOG_PERSONAL_API_KEY` configured, the client throws with a pointer to the remote `evaluateFlag` / `evaluateFlagPayload` / `evaluateAllFlags` methods. While the first cron tick is still in flight (PAK is set but no definitions are cached yet) the local methods return `undefined` so your fallback path keeps working.
|
|
95
|
-
|
|
96
|
-
Need to force a refresh between cron ticks (e.g. just after creating a flag in development)? Call `posthog.reloadFeatureFlags(ctx)` from an action — same name and shape as `posthog-node`.
|
|
97
|
-
|
|
98
|
-
## 📊 Capturing Events
|
|
99
|
-
|
|
100
|
-
Import `posthog` from your setup file and call methods directly:
|
|
101
|
-
|
|
102
|
-
```ts
|
|
103
|
-
// convex/myFunctions.ts
|
|
104
|
-
import { posthog } from "./posthog";
|
|
105
|
-
import { mutation } from "./_generated/server";
|
|
106
|
-
import { v } from "convex/values";
|
|
107
|
-
|
|
108
|
-
export const createUser = mutation({
|
|
109
|
-
args: { email: v.string() },
|
|
110
|
-
handler: async (ctx, args) => {
|
|
111
|
-
const userId = await ctx.db.insert("users", { email: args.email });
|
|
112
|
-
|
|
113
|
-
await posthog.capture(ctx, {
|
|
114
|
-
distinctId: userId,
|
|
115
|
-
event: "user_created",
|
|
116
|
-
properties: { email: args.email },
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
return userId;
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### capture
|
|
125
|
-
|
|
126
|
-
Capture an event. Works in mutations and actions.
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
await posthog.capture(ctx, {
|
|
130
|
-
distinctId: "user_123",
|
|
131
|
-
event: "purchase_completed",
|
|
132
|
-
properties: { amount: 99.99, currency: "USD" },
|
|
133
|
-
groups: { company: "acme-corp" },
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Options: `distinctId`, `event`, `properties`, `groups`, `sendFeatureFlags`, `timestamp`, `uuid`, `disableGeoip`.
|
|
138
|
-
|
|
139
|
-
### identify
|
|
140
|
-
|
|
141
|
-
Set user properties.
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
await posthog.identify(ctx, {
|
|
145
|
-
distinctId: "user_123",
|
|
146
|
-
properties: { name: "Jane Doe", plan: "pro" },
|
|
147
|
-
});
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### groupIdentify
|
|
151
|
-
|
|
152
|
-
Set group properties.
|
|
153
|
-
|
|
154
|
-
```ts
|
|
155
|
-
await posthog.groupIdentify(ctx, {
|
|
156
|
-
groupType: "company",
|
|
157
|
-
groupKey: "acme-corp",
|
|
158
|
-
properties: { industry: "Technology", employees: 500 },
|
|
159
|
-
});
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### alias
|
|
163
|
-
|
|
164
|
-
Link two distinct IDs.
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
await posthog.alias(ctx, {
|
|
168
|
-
distinctId: "user_123",
|
|
169
|
-
alias: "anonymous_456",
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### captureException
|
|
174
|
-
|
|
175
|
-
Send an exception to PostHog's error tracking pipeline. Accepts an `Error`, a string, or any object with a `message` field.
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
try {
|
|
179
|
-
await chargeCard(...);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
await posthog.captureException(ctx, {
|
|
182
|
-
error,
|
|
183
|
-
distinctId: "user_123",
|
|
184
|
-
additionalProperties: { plan: "pro" },
|
|
185
|
-
});
|
|
186
|
-
throw error;
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
If you'd rather have **every** uncaught error from your Convex deployment forwarded to PostHog automatically — including ones you didn't explicitly wrap — wire up Convex's first-party PostHog exception reporting integration from the Convex dashboard. Setup lives at [docs.convex.dev/production/integrations/exception-reporting#configuring-posthog-error-tracking](https://docs.convex.dev/production/integrations/exception-reporting#configuring-posthog-error-tracking). Use `captureException` here for cases where you want explicit control (e.g. attaching custom `additionalProperties`); use the Convex-side integration for catch-all coverage.
|
|
191
|
-
|
|
192
|
-
All of the above methods schedule the PostHog API call asynchronously via `ctx.scheduler.runAfter`, so they return immediately without blocking your mutation or action.
|
|
193
|
-
|
|
194
|
-
## 🚩 Feature Flags
|
|
195
|
-
|
|
196
|
-
Two evaluation paths, pick the one that fits the flag:
|
|
197
|
-
|
|
198
|
-
- **Local** (`getFeatureFlag`, `isFeatureEnabled`, …) — evaluates against definitions cached by the cron. Works in **queries, mutations, and actions**, no per-call network round-trip, reactive (a query reading a flag re-runs when definitions change). Requires `POSTHOG_PERSONAL_API_KEY`. Can't handle every flag — see [the limitations](#local-evaluation--limitations) below.
|
|
199
|
-
- **Remote** (`evaluateFlag`, `evaluateFlagPayload`, `evaluateAllFlags`) — hits PostHog's `/flags` endpoint directly. Action-context only, no `personalApiKey` needed, handles every flag.
|
|
200
|
-
|
|
201
|
-
The local methods are documented first; remote is at the bottom of this section.
|
|
202
|
-
|
|
203
|
-
### getFeatureFlag
|
|
204
|
-
|
|
205
|
-
Get a flag's value.
|
|
206
|
-
|
|
207
|
-
```ts
|
|
208
|
-
import { posthog } from "./posthog";
|
|
209
|
-
import { query } from "./_generated/server";
|
|
210
|
-
import { v } from "convex/values";
|
|
211
|
-
|
|
212
|
-
export const getDiscount = query({
|
|
213
|
-
args: { userId: v.string() },
|
|
214
|
-
handler: async (ctx, args) => {
|
|
215
|
-
const flag = await posthog.getFeatureFlag(ctx, {
|
|
216
|
-
key: "discount-campaign",
|
|
217
|
-
distinctId: args.userId,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
if (flag === "variant-a") {
|
|
221
|
-
return { discount: 20 };
|
|
222
|
-
}
|
|
223
|
-
return { discount: 0 };
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### isFeatureEnabled
|
|
229
|
-
|
|
230
|
-
Check if a flag is enabled.
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
const enabled = await posthog.isFeatureEnabled(ctx, {
|
|
234
|
-
key: "new-onboarding",
|
|
235
|
-
distinctId: "user_123",
|
|
236
|
-
});
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### getFeatureFlagPayload
|
|
240
|
-
|
|
241
|
-
Get a flag's JSON payload.
|
|
242
|
-
|
|
243
|
-
```ts
|
|
244
|
-
const payload = await posthog.getFeatureFlagPayload(ctx, {
|
|
245
|
-
key: "pricing-config",
|
|
246
|
-
distinctId: "user_123",
|
|
247
|
-
});
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### getFeatureFlagResult
|
|
251
|
-
|
|
252
|
-
Get a flag's value and payload in one call.
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
const result = await posthog.getFeatureFlagResult(ctx, {
|
|
256
|
-
key: "experiment-flag",
|
|
257
|
-
distinctId: "user_123",
|
|
258
|
-
});
|
|
259
|
-
if (result) {
|
|
260
|
-
console.log(result.enabled, result.variant, result.payload);
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### getAllFlags
|
|
265
|
-
|
|
266
|
-
Get all flag values for a user.
|
|
267
|
-
|
|
268
|
-
```ts
|
|
269
|
-
const flags = await posthog.getAllFlags(ctx, {
|
|
270
|
-
distinctId: "user_123",
|
|
271
|
-
});
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### getAllFlagsAndPayloads
|
|
275
|
-
|
|
276
|
-
Get all flags and their payloads.
|
|
277
|
-
|
|
278
|
-
```ts
|
|
279
|
-
const { featureFlags, featureFlagPayloads } =
|
|
280
|
-
await posthog.getAllFlagsAndPayloads(ctx, {
|
|
281
|
-
distinctId: "user_123",
|
|
282
|
-
});
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
All feature flag methods accept optional `groups`, `personProperties`, `groupProperties`, and `disableGeoip` options. `getAllFlags` and `getAllFlagsAndPayloads` also accept `flagKeys` to filter which flags to evaluate.
|
|
286
|
-
|
|
287
|
-
### Local evaluation — limitations
|
|
288
|
-
|
|
289
|
-
Local eval can't reach a verdict for every flag, and for those this component will return `null`. The cases:
|
|
290
|
-
|
|
291
|
-
- **Experience continuity flags.** Flags with [persist across authentication steps](https://posthog.com/docs/feature-flags/creating-feature-flags#persisting-feature-flags-across-authentication-steps) need server-side anon→identified tracking and aren't included in local eval.
|
|
292
|
-
- **Static cohorts.** Cohort membership for static cohorts lives only on the server.
|
|
293
|
-
- **Properties not passed in.** Local eval can only see what you give it. If a flag targets `email` or `$browser_version` and you don't pass those in `personProperties`, it can't resolve.
|
|
294
|
-
- **Cohorts that don't fit the local-eval shape.** Cohorts with variant overrides, non-person properties, more than one cohort in the same flag definition, nested AND/OR filters, or grouped with other conditions can't be translated for local eval. See [the PostHog docs](https://posthog.com/docs/feature-flags/local-evaluation#dynamic-cohort-restrictions) for the full list.
|
|
295
|
-
|
|
296
|
-
Local eval doesn't fire `$feature_flag_called` events. PostHog Experiments counts exposures off these — `posthog-node` emits them automatically on every local eval, but this component can't do the same: Convex queries are pure functions, so they can't schedule a `capture` from inside the eval path without breaking Convex's contract. If you're running an experiment against a locally-evaluated flag, fire one manually from a mutation or action:
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
await posthog.capture(ctx, {
|
|
300
|
-
event: "$feature_flag_called",
|
|
301
|
-
distinctId: userId,
|
|
302
|
-
properties: {
|
|
303
|
-
$feature_flag: "flag-key",
|
|
304
|
-
$feature_flag_response: value,
|
|
305
|
-
locally_evaluated: true,
|
|
306
|
-
},
|
|
307
|
-
});
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
There are also reasons you might *not want* local eval at all, even when it's possible:
|
|
311
|
-
|
|
312
|
-
- **Low-traffic projects.** PostHog bills each `/flags/definitions` poll as 10 flag-request equivalents. For projects that evaluate fewer flags than that per polling interval, remote evaluation is cheaper.
|
|
313
|
-
- **Need-it-now changes.** Local eval accepts up to one polling interval of staleness (default 1 minute with our cron). For flags that must flip in well under that, you want remote eval.
|
|
314
|
-
- **No personal API key.** If you don't want to set `POSTHOG_PERSONAL_API_KEY`, the local methods aren't useful — there's nothing for them to read.
|
|
315
|
-
|
|
316
|
-
For any of those, use the remote-eval methods below instead.
|
|
317
|
-
|
|
318
|
-
### Remote evaluation
|
|
319
|
-
|
|
320
|
-
Sibling methods that hit PostHog's `/flags` endpoint directly. They require an **action** context (each call is a network round trip) and don't need `personalApiKey`. They handle every case local eval can't.
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
import { posthog } from "./posthog";
|
|
324
|
-
import { action } from "./_generated/server";
|
|
325
|
-
import { v } from "convex/values";
|
|
326
|
-
|
|
327
|
-
export const getContinuityFlag = action({
|
|
328
|
-
args: { userId: v.string() },
|
|
329
|
-
handler: async (ctx, args) => {
|
|
330
|
-
const value = await posthog.evaluateFlag(ctx, {
|
|
331
|
-
key: "my-experience-continuity-flag",
|
|
332
|
-
distinctId: args.userId,
|
|
333
|
-
personProperties: { plan: "pro" },
|
|
334
|
-
});
|
|
335
|
-
return value;
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
Three methods:
|
|
341
|
-
|
|
342
|
-
| Method | Returns |
|
|
343
|
-
| --- | --- |
|
|
344
|
-
| `posthog.evaluateFlag(ctx, args)` | `FeatureFlagValue \| null` |
|
|
345
|
-
| `posthog.evaluateFlagPayload(ctx, args)` | `JsonType \| null` |
|
|
346
|
-
| `posthog.evaluateAllFlags(ctx, args)` | `{ featureFlags, featureFlagPayloads }` |
|
|
347
|
-
|
|
348
|
-
Same option shape as the local methods (`groups`, `personProperties`, `groupProperties`, `disableGeoip`, `flagKeys` on the all-flags variant). Pick local when the flag is suitable and the cost of `/flags/definitions` polling is justified; pick remote when it isn't.
|
|
349
|
-
|
|
350
|
-
## 🔄 Differences from `posthog-node`
|
|
351
|
-
|
|
352
|
-
Method names and option shapes (`groups`, `personProperties`, `groupProperties`, `disableGeoip`, `flagKeys`) match `posthog-node` where they reasonably can. The differences:
|
|
353
|
-
|
|
354
|
-
- **Every method takes a Convex `ctx` first.** `posthog.capture(ctx, { … })` rather than `posthog.capture({ … })`. Required by Convex's runtime.
|
|
355
|
-
- **Flag methods and `captureException` use an args object instead of positional args.** `getFeatureFlag(ctx, { key, distinctId, … })` rather than `getFeatureFlag(key, distinctId, …)`. The event methods (`capture`, `identify`, `alias`, `groupIdentify`) already use args objects in `posthog-node`, so those match.
|
|
356
|
-
- **No `captureImmediate` / `identifyImmediate` / `aliasImmediate` variants.** All component actions use the `Immediate` paths under the hood — Convex isolates don't have a clean lifecycle hook for batching and flushing, so the queued mode is gone.
|
|
357
|
-
- **No `flush()` / `shutdown()`.** Same reason — there's nothing to flush.
|
|
358
|
-
- **Local-eval methods don't auto-fall-back to remote.** `posthog-node`'s `getFeatureFlag` quietly hits `/flags` when local eval can't reach a verdict. Ours returns `undefined` (or `null` from `getFeatureFlagResult`) and you call `evaluateFlag` / `evaluateFlagPayload` / `evaluateAllFlags` explicitly for remote. Auto-fallback would force every local-eval call into an action context (since queries can't make network calls), which would defeat the reactivity win.
|
|
359
|
-
- **Local-eval methods throw when `POSTHOG_PERSONAL_API_KEY` isn't configured.** `posthog-node` returns `undefined`; the throw here points you at the remote `evaluate*` methods so you can't get stuck wondering why your rollouts don't take effect.
|
|
360
|
-
|
|
361
|
-
## ⬆️ Migrating from v1
|
|
362
|
-
|
|
363
|
-
v2 moves credentials from the client constructor onto the component itself, using [Convex 1.39's typed component env vars](https://docs.convex.dev/components/authoring#environment-variables). It also bundles the refresh cron inside the component. The result is less plumbing per call site and a setup that's safe to leave running on free-tier dev deployments.
|
|
364
|
-
|
|
365
|
-
To upgrade:
|
|
366
|
-
|
|
367
|
-
1. **Bump your app's `convex` dependency** to `^1.39.0` (required for the typed component env-var API).
|
|
368
|
-
2. **Rename** the `POSTHOG_API_KEY` env var to `POSTHOG_PROJECT_TOKEN`. The new name is unambiguous: this is your PostHog project token (`phc_…`), distinct from `POSTHOG_PERSONAL_API_KEY` (the `phx_…` / `phs_…` key used for local flag evaluation).
|
|
369
|
-
```sh
|
|
370
|
-
npx convex env set POSTHOG_PROJECT_TOKEN phc_your_project_token
|
|
371
|
-
npx convex env unset POSTHOG_API_KEY
|
|
372
|
-
```
|
|
373
|
-
`POSTHOG_PROJECT_TOKEN` is now **required at deploy time** (declared as `v.string()` on the component). In v1 the component would deploy without it set and silently no-op event sends at runtime; v2 fails fast at deploy. Make sure the env var is set before deploying.
|
|
374
|
-
3. **Declare the env vars on your app and forward them to the component** in `convex/convex.config.ts`:
|
|
375
|
-
```ts
|
|
376
|
-
const app = defineApp({
|
|
377
|
-
env: {
|
|
378
|
-
POSTHOG_PROJECT_TOKEN: v.string(),
|
|
379
|
-
POSTHOG_HOST: v.optional(v.string()),
|
|
380
|
-
POSTHOG_PERSONAL_API_KEY: v.optional(v.string()),
|
|
381
|
-
},
|
|
382
|
-
});
|
|
383
|
-
app.use(posthog, {
|
|
384
|
-
env: {
|
|
385
|
-
POSTHOG_PROJECT_TOKEN: app.env.POSTHOG_PROJECT_TOKEN,
|
|
386
|
-
POSTHOG_HOST: app.env.POSTHOG_HOST,
|
|
387
|
-
POSTHOG_PERSONAL_API_KEY: app.env.POSTHOG_PERSONAL_API_KEY,
|
|
388
|
-
},
|
|
389
|
-
});
|
|
390
|
-
```
|
|
391
|
-
4. **Drop the credential options** from `new PostHog(...)`:
|
|
392
|
-
```diff
|
|
393
|
-
- export const posthog = new PostHog(components.posthog, {
|
|
394
|
-
- apiKey: process.env.POSTHOG_API_KEY,
|
|
395
|
-
- personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,
|
|
396
|
-
- host: process.env.POSTHOG_HOST,
|
|
397
|
-
- });
|
|
398
|
-
+ export const posthog = new PostHog(components.posthog);
|
|
399
|
-
```
|
|
400
|
-
5. **Delete your `convex/crons.ts`** if it only existed to refresh PostHog flag definitions — the component ships its own cron now, conditionally registered only when `POSTHOG_PERSONAL_API_KEY` is set. `posthog.refreshFlagDefinitions(ctx)` was renamed to `posthog.reloadFeatureFlags(ctx)` for parity with `posthog-node`; the cron is the primary refresh path but you can still call this manually from an action when you need an immediate refresh.
|
|
401
|
-
|
|
402
|
-
Everything else — the `capture`, `identify`, `getFeatureFlag`, `evaluateFlag`, etc. APIs — is unchanged.
|
|
403
|
-
|
|
404
|
-
## 📦 Example
|
|
405
|
-
|
|
406
|
-
See the [example app](../../examples/example-convex/) for a working demo.
|
|
407
|
-
|
|
408
|
-
## 🤝 Contributing
|
|
8
|
+
Please see the main [PostHog docs](https://posthog.com/docs).
|
|
409
9
|
|
|
410
|
-
|
|
10
|
+
SDK usage examples and code snippets live in the official documentation so they stay up to date.
|
|
411
11
|
|
|
412
|
-
##
|
|
12
|
+
## Documentation
|
|
413
13
|
|
|
414
|
-
|
|
14
|
+
- [Convex library docs](https://posthog.com/docs/libraries/convex)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "2.0.
|
|
1
|
+
export declare const version = "2.0.29";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '2.0.
|
|
1
|
+
export const version = '2.0.29';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "https://github.com/PostHog/posthog-js/issues"
|
|
12
12
|
},
|
|
13
13
|
"author": "PostHog Inc.",
|
|
14
|
-
"version": "2.0.
|
|
14
|
+
"version": "2.0.29",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"keywords": [
|
|
17
17
|
"convex",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"types": "./dist/client/index.d.ts",
|
|
49
49
|
"module": "./dist/client/index.js",
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@posthog/core": "1.
|
|
52
|
-
"posthog-node": "5.
|
|
51
|
+
"@posthog/core": "^1.35.2",
|
|
52
|
+
"posthog-node": "^5.38.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@edge-runtime/vm": "^5.0.0",
|
package/src/component/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.0.
|
|
1
|
+
export const version = '2.0.29'
|