@posthog/convex 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +299 -0
  2. package/README.md +237 -29
  3. package/dist/client/index.d.ts +126 -0
  4. package/dist/client/index.d.ts.map +1 -0
  5. package/dist/client/index.js +213 -0
  6. package/dist/client/index.js.map +1 -0
  7. package/dist/component/_generated/api.d.ts +34 -0
  8. package/dist/component/_generated/api.d.ts.map +1 -0
  9. package/dist/component/_generated/api.js +31 -0
  10. package/dist/component/_generated/api.js.map +1 -0
  11. package/dist/component/_generated/component.d.ts +134 -0
  12. package/dist/component/_generated/component.d.ts.map +1 -0
  13. package/dist/component/_generated/component.js +11 -0
  14. package/dist/component/_generated/component.js.map +1 -0
  15. package/dist/component/_generated/dataModel.d.ts +46 -0
  16. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  17. package/dist/component/_generated/dataModel.js +11 -0
  18. package/dist/component/_generated/dataModel.js.map +1 -0
  19. package/dist/component/_generated/server.d.ts +121 -0
  20. package/dist/component/_generated/server.d.ts.map +1 -0
  21. package/dist/component/_generated/server.js +78 -0
  22. package/dist/component/_generated/server.js.map +1 -0
  23. package/dist/component/convex.config.d.ts +3 -0
  24. package/dist/component/convex.config.d.ts.map +1 -0
  25. package/dist/component/convex.config.js +3 -0
  26. package/dist/component/convex.config.js.map +1 -0
  27. package/dist/component/lib.d.ts +119 -0
  28. package/dist/component/lib.d.ts.map +1 -0
  29. package/dist/component/lib.js +221 -0
  30. package/dist/component/lib.js.map +1 -0
  31. package/dist/component/schema.d.ts +3 -0
  32. package/dist/component/schema.d.ts.map +1 -0
  33. package/dist/component/schema.js +3 -0
  34. package/dist/component/schema.js.map +1 -0
  35. package/package.json +78 -7
  36. package/src/client/index.test.ts +505 -0
  37. package/src/client/index.ts +363 -0
  38. package/src/client/setup.test.ts +20 -0
  39. package/src/component/_generated/api.ts +50 -0
  40. package/src/component/_generated/component.ts +203 -0
  41. package/src/component/_generated/dataModel.ts +60 -0
  42. package/src/component/_generated/server.ts +156 -0
  43. package/src/component/convex.config.ts +3 -0
  44. package/src/component/lib.ts +259 -0
  45. package/src/component/schema.ts +3 -0
  46. package/src/component/setup.test.ts +11 -0
  47. package/src/test.ts +15 -0
@@ -0,0 +1,363 @@
1
+ import type { Scheduler } from 'convex/server'
2
+ import type { ComponentApi } from '../component/_generated/component.js'
3
+
4
+ /** Context with a scheduler — available in mutations and actions. */
5
+ type SchedulerCtx = { scheduler: Scheduler }
6
+
7
+ /** Context with runAction — available in actions only. */
8
+ type ActionCtx = { runAction: (reference: any, args: any) => Promise<any> }
9
+
10
+ type FeatureFlagOptions = {
11
+ groups?: Record<string, string>
12
+ personProperties?: Record<string, string>
13
+ groupProperties?: Record<string, Record<string, string>>
14
+ sendFeatureFlagEvents?: boolean
15
+ disableGeoip?: boolean
16
+ }
17
+
18
+ export type FeatureFlagResult = {
19
+ key: string
20
+ enabled: boolean
21
+ variant: string | null
22
+ payload: unknown
23
+ }
24
+
25
+ export type PostHogEvent = {
26
+ event: string
27
+ distinctId: string
28
+ properties?: Record<string, unknown>
29
+ }
30
+
31
+ export type BeforeSendFn = (event: PostHogEvent) => PostHogEvent | null
32
+
33
+ export type IdentifyFn = (ctx: any) => Promise<{ distinctId: string } | null>
34
+
35
+ export function normalizeError(error: unknown): {
36
+ message: string
37
+ stack?: string
38
+ name?: string
39
+ } {
40
+ if (error instanceof Error) {
41
+ return { message: error.message, stack: error.stack, name: error.name }
42
+ }
43
+ if (typeof error === 'string') {
44
+ return { message: error }
45
+ }
46
+ if (
47
+ typeof error === 'object' &&
48
+ error !== null &&
49
+ 'message' in error &&
50
+ typeof (error as { message: unknown }).message === 'string'
51
+ ) {
52
+ const obj = error as {
53
+ message: string
54
+ stack?: unknown
55
+ name?: unknown
56
+ }
57
+ return {
58
+ message: obj.message,
59
+ stack: typeof obj.stack === 'string' ? obj.stack : undefined,
60
+ name: typeof obj.name === 'string' ? obj.name : undefined,
61
+ }
62
+ }
63
+ return { message: String(error) }
64
+ }
65
+
66
+ export class PostHog {
67
+ private apiKey: string
68
+ private host: string
69
+ private beforeSend?: BeforeSendFn | BeforeSendFn[]
70
+ private identifyFn?: IdentifyFn
71
+
72
+ constructor(
73
+ public component: ComponentApi,
74
+ options?: {
75
+ apiKey?: string
76
+ host?: string
77
+ beforeSend?: BeforeSendFn | BeforeSendFn[]
78
+ identify?: IdentifyFn
79
+ }
80
+ ) {
81
+ this.apiKey = options?.apiKey ?? process.env.POSTHOG_API_KEY ?? ''
82
+ this.host = options?.host ?? process.env.POSTHOG_HOST ?? 'https://us.i.posthog.com'
83
+ this.beforeSend = options?.beforeSend
84
+ this.identifyFn = options?.identify
85
+ }
86
+
87
+ private async resolveDistinctId(ctx: unknown, argsDistinctId?: string): Promise<string> {
88
+ if (this.identifyFn) {
89
+ const result = await this.identifyFn(ctx)
90
+ if (result) return result.distinctId
91
+ }
92
+ if (argsDistinctId) return argsDistinctId
93
+ throw new Error(
94
+ 'PostHog: Could not resolve distinctId. Either configure an identify callback ' +
95
+ 'in the PostHog constructor or pass distinctId explicitly.'
96
+ )
97
+ }
98
+
99
+ private runBeforeSend(event: PostHogEvent): PostHogEvent | null {
100
+ if (!this.beforeSend) return event
101
+ const fns = Array.isArray(this.beforeSend) ? this.beforeSend : [this.beforeSend]
102
+ let result: PostHogEvent | null = event
103
+ for (const fn of fns) {
104
+ result = fn(result)
105
+ if (!result) return null
106
+ }
107
+ return result
108
+ }
109
+
110
+ // --- Fire-and-forget methods (work in mutations and actions) ---
111
+
112
+ async capture(
113
+ ctx: SchedulerCtx,
114
+ args: {
115
+ distinctId?: string
116
+ event: string
117
+ properties?: Record<string, unknown>
118
+ groups?: Record<string, string | number>
119
+ sendFeatureFlags?: boolean
120
+ timestamp?: Date
121
+ uuid?: string
122
+ disableGeoip?: boolean
123
+ }
124
+ ) {
125
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
126
+ const result = this.runBeforeSend({
127
+ event: args.event,
128
+ distinctId,
129
+ properties: args.properties,
130
+ })
131
+ if (!result) return
132
+
133
+ await ctx.scheduler.runAfter(0, this.component.lib.capture, {
134
+ apiKey: this.apiKey,
135
+ host: this.host,
136
+ distinctId: result.distinctId,
137
+ event: result.event,
138
+ properties: result.properties,
139
+ groups: args.groups,
140
+ sendFeatureFlags: args.sendFeatureFlags,
141
+ timestamp: args.timestamp?.getTime(),
142
+ uuid: args.uuid,
143
+ disableGeoip: args.disableGeoip,
144
+ })
145
+ }
146
+
147
+ async identify(
148
+ ctx: SchedulerCtx,
149
+ args: {
150
+ distinctId?: string
151
+ properties?: Record<string, unknown> & {
152
+ $set?: Record<string, unknown>
153
+ $set_once?: Record<string, unknown>
154
+ $anon_distinct_id?: string
155
+ }
156
+ disableGeoip?: boolean
157
+ }
158
+ ) {
159
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
160
+ const result = this.runBeforeSend({
161
+ event: '$identify',
162
+ distinctId,
163
+ properties: args.properties,
164
+ })
165
+ if (!result) return
166
+
167
+ await ctx.scheduler.runAfter(0, this.component.lib.identify, {
168
+ apiKey: this.apiKey,
169
+ host: this.host,
170
+ distinctId: result.distinctId,
171
+ properties: result.properties,
172
+ disableGeoip: args.disableGeoip,
173
+ })
174
+ }
175
+
176
+ async groupIdentify(
177
+ ctx: SchedulerCtx,
178
+ args: {
179
+ groupType: string
180
+ groupKey: string
181
+ properties?: Record<string, unknown>
182
+ distinctId?: string
183
+ disableGeoip?: boolean
184
+ }
185
+ ) {
186
+ const result = this.runBeforeSend({
187
+ event: '$groupidentify',
188
+ distinctId: args.distinctId ?? '',
189
+ properties: args.properties,
190
+ })
191
+ if (!result) return
192
+
193
+ await ctx.scheduler.runAfter(0, this.component.lib.groupIdentify, {
194
+ apiKey: this.apiKey,
195
+ host: this.host,
196
+ groupType: args.groupType,
197
+ groupKey: args.groupKey,
198
+ properties: result.properties,
199
+ distinctId: args.distinctId,
200
+ disableGeoip: args.disableGeoip,
201
+ })
202
+ }
203
+
204
+ async alias(
205
+ ctx: SchedulerCtx,
206
+ args: {
207
+ distinctId?: string
208
+ alias: string
209
+ disableGeoip?: boolean
210
+ }
211
+ ) {
212
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
213
+ const result = this.runBeforeSend({
214
+ event: '$create_alias',
215
+ distinctId,
216
+ })
217
+ if (!result) return
218
+
219
+ await ctx.scheduler.runAfter(0, this.component.lib.alias, {
220
+ apiKey: this.apiKey,
221
+ host: this.host,
222
+ distinctId: result.distinctId,
223
+ alias: args.alias,
224
+ disableGeoip: args.disableGeoip,
225
+ })
226
+ }
227
+
228
+ async captureException(
229
+ ctx: SchedulerCtx,
230
+ args: {
231
+ error: unknown
232
+ distinctId?: string
233
+ additionalProperties?: Record<string, unknown>
234
+ }
235
+ ) {
236
+ const { message, stack, name } = normalizeError(args.error)
237
+
238
+ let distinctId: string | undefined
239
+ try {
240
+ distinctId = await this.resolveDistinctId(ctx, args.distinctId)
241
+ } catch {
242
+ // captureException works without a distinctId
243
+ }
244
+
245
+ const result = this.runBeforeSend({
246
+ event: '$exception',
247
+ distinctId: distinctId ?? '',
248
+ properties: args.additionalProperties,
249
+ })
250
+ if (!result) return
251
+
252
+ await ctx.scheduler.runAfter(0, this.component.lib.captureException, {
253
+ apiKey: this.apiKey,
254
+ host: this.host,
255
+ distinctId: result.distinctId || undefined,
256
+ errorMessage: message,
257
+ errorStack: stack,
258
+ errorName: name,
259
+ additionalProperties: result.properties,
260
+ })
261
+ }
262
+
263
+ // --- Feature flag methods (require action context) ---
264
+
265
+ async getFeatureFlag(
266
+ ctx: ActionCtx,
267
+ args: { key: string; distinctId?: string } & FeatureFlagOptions
268
+ ): Promise<boolean | string | null> {
269
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
270
+ return await ctx.runAction(this.component.lib.getFeatureFlag, {
271
+ apiKey: this.apiKey,
272
+ host: this.host,
273
+ ...args,
274
+ distinctId,
275
+ })
276
+ }
277
+
278
+ async isFeatureEnabled(
279
+ ctx: ActionCtx,
280
+ args: { key: string; distinctId?: string } & FeatureFlagOptions
281
+ ): Promise<boolean | null> {
282
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
283
+ return await ctx.runAction(this.component.lib.isFeatureEnabled, {
284
+ apiKey: this.apiKey,
285
+ host: this.host,
286
+ ...args,
287
+ distinctId,
288
+ })
289
+ }
290
+
291
+ async getFeatureFlagPayload(
292
+ ctx: ActionCtx,
293
+ args: {
294
+ key: string
295
+ distinctId?: string
296
+ matchValue?: boolean | string
297
+ } & FeatureFlagOptions
298
+ ): Promise<unknown> {
299
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
300
+ return await ctx.runAction(this.component.lib.getFeatureFlagPayload, {
301
+ apiKey: this.apiKey,
302
+ host: this.host,
303
+ ...args,
304
+ distinctId,
305
+ })
306
+ }
307
+
308
+ async getFeatureFlagResult(
309
+ ctx: ActionCtx,
310
+ args: { key: string; distinctId?: string } & FeatureFlagOptions
311
+ ): Promise<FeatureFlagResult | null> {
312
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
313
+ return await ctx.runAction(this.component.lib.getFeatureFlagResult, {
314
+ apiKey: this.apiKey,
315
+ host: this.host,
316
+ ...args,
317
+ distinctId,
318
+ })
319
+ }
320
+
321
+ async getAllFlags(
322
+ ctx: ActionCtx,
323
+ args: {
324
+ distinctId?: string
325
+ groups?: Record<string, string>
326
+ personProperties?: Record<string, string>
327
+ groupProperties?: Record<string, Record<string, string>>
328
+ disableGeoip?: boolean
329
+ flagKeys?: string[]
330
+ }
331
+ ): Promise<Record<string, boolean | string>> {
332
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
333
+ return await ctx.runAction(this.component.lib.getAllFlags, {
334
+ apiKey: this.apiKey,
335
+ host: this.host,
336
+ ...args,
337
+ distinctId,
338
+ })
339
+ }
340
+
341
+ async getAllFlagsAndPayloads(
342
+ ctx: ActionCtx,
343
+ args: {
344
+ distinctId?: string
345
+ groups?: Record<string, string>
346
+ personProperties?: Record<string, string>
347
+ groupProperties?: Record<string, Record<string, string>>
348
+ disableGeoip?: boolean
349
+ flagKeys?: string[]
350
+ }
351
+ ): Promise<{
352
+ featureFlags: Record<string, boolean | string>
353
+ featureFlagPayloads: Record<string, unknown>
354
+ }> {
355
+ const distinctId = await this.resolveDistinctId(ctx, args.distinctId)
356
+ return await ctx.runAction(this.component.lib.getAllFlagsAndPayloads, {
357
+ apiKey: this.apiKey,
358
+ host: this.host,
359
+ ...args,
360
+ distinctId,
361
+ })
362
+ }
363
+ }
@@ -0,0 +1,20 @@
1
+ /// <reference types="vite/client" />
2
+ import { test } from '@jest/globals'
3
+ import { convexTest } from 'convex-test'
4
+ export const modules = import.meta.glob('./**/*.*s')
5
+
6
+ import { defineSchema, type GenericSchema, type SchemaDefinition } from 'convex/server'
7
+ import { type ComponentApi } from '../component/_generated/component.js'
8
+ import { componentsGeneric } from 'convex/server'
9
+ import { register } from '../test.js'
10
+
11
+ export function initConvexTest<Schema extends SchemaDefinition<GenericSchema, boolean>>(schema?: Schema) {
12
+ const t = convexTest(schema ?? defineSchema({}), modules)
13
+ register(t)
14
+ return t
15
+ }
16
+ export const components = componentsGeneric() as unknown as {
17
+ posthog: ComponentApi
18
+ }
19
+
20
+ test('setup', () => {})
@@ -0,0 +1,50 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `api` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type * as lib from "../lib.js";
12
+
13
+ import type {
14
+ ApiFromModules,
15
+ FilterApi,
16
+ FunctionReference,
17
+ } from "convex/server";
18
+ import { anyApi, componentsGeneric } from "convex/server";
19
+
20
+ const fullApi: ApiFromModules<{
21
+ lib: typeof lib;
22
+ }> = anyApi as any;
23
+
24
+ /**
25
+ * A utility for referencing Convex functions in your app's public API.
26
+ *
27
+ * Usage:
28
+ * ```js
29
+ * const myFunctionReference = api.myModule.myFunction;
30
+ * ```
31
+ */
32
+ export const api: FilterApi<
33
+ typeof fullApi,
34
+ FunctionReference<any, "public">
35
+ > = anyApi as any;
36
+
37
+ /**
38
+ * A utility for referencing Convex functions in your app's internal API.
39
+ *
40
+ * Usage:
41
+ * ```js
42
+ * const myFunctionReference = internal.myModule.myFunction;
43
+ * ```
44
+ */
45
+ export const internal: FilterApi<
46
+ typeof fullApi,
47
+ FunctionReference<any, "internal">
48
+ > = anyApi as any;
49
+
50
+ export const components = componentsGeneric() as unknown as {};
@@ -0,0 +1,203 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated `ComponentApi` utility.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type { FunctionReference } from "convex/server";
12
+
13
+ /**
14
+ * A utility for referencing a Convex component's exposed API.
15
+ *
16
+ * Useful when expecting a parameter like `components.myComponent`.
17
+ * Usage:
18
+ * ```ts
19
+ * async function myFunction(ctx: QueryCtx, component: ComponentApi) {
20
+ * return ctx.runQuery(component.someFile.someQuery, { ...args });
21
+ * }
22
+ * ```
23
+ */
24
+ export type ComponentApi<Name extends string | undefined = string | undefined> =
25
+ {
26
+ lib: {
27
+ alias: FunctionReference<
28
+ "action",
29
+ "internal",
30
+ {
31
+ alias: string;
32
+ apiKey: string;
33
+ disableGeoip?: boolean;
34
+ distinctId: string;
35
+ host: string;
36
+ },
37
+ any,
38
+ Name
39
+ >;
40
+ capture: FunctionReference<
41
+ "action",
42
+ "internal",
43
+ {
44
+ apiKey: string;
45
+ disableGeoip?: boolean;
46
+ distinctId: string;
47
+ event: string;
48
+ groups?: any;
49
+ host: string;
50
+ properties?: any;
51
+ sendFeatureFlags?: boolean;
52
+ timestamp?: number;
53
+ uuid?: string;
54
+ },
55
+ any,
56
+ Name
57
+ >;
58
+ captureException: FunctionReference<
59
+ "action",
60
+ "internal",
61
+ {
62
+ additionalProperties?: any;
63
+ apiKey: string;
64
+ distinctId?: string;
65
+ errorMessage: string;
66
+ errorName?: string;
67
+ errorStack?: string;
68
+ host: string;
69
+ },
70
+ any,
71
+ Name
72
+ >;
73
+ getAllFlags: FunctionReference<
74
+ "action",
75
+ "internal",
76
+ {
77
+ apiKey: string;
78
+ disableGeoip?: boolean;
79
+ distinctId: string;
80
+ flagKeys?: Array<string>;
81
+ groupProperties?: any;
82
+ groups?: any;
83
+ host: string;
84
+ personProperties?: any;
85
+ },
86
+ any,
87
+ Name
88
+ >;
89
+ getAllFlagsAndPayloads: FunctionReference<
90
+ "action",
91
+ "internal",
92
+ {
93
+ apiKey: string;
94
+ disableGeoip?: boolean;
95
+ distinctId: string;
96
+ flagKeys?: Array<string>;
97
+ groupProperties?: any;
98
+ groups?: any;
99
+ host: string;
100
+ personProperties?: any;
101
+ },
102
+ any,
103
+ Name
104
+ >;
105
+ getFeatureFlag: FunctionReference<
106
+ "action",
107
+ "internal",
108
+ {
109
+ apiKey: string;
110
+ disableGeoip?: boolean;
111
+ distinctId: string;
112
+ groupProperties?: any;
113
+ groups?: any;
114
+ host: string;
115
+ key: string;
116
+ personProperties?: any;
117
+ sendFeatureFlagEvents?: boolean;
118
+ },
119
+ any,
120
+ Name
121
+ >;
122
+ getFeatureFlagPayload: FunctionReference<
123
+ "action",
124
+ "internal",
125
+ {
126
+ apiKey: string;
127
+ disableGeoip?: boolean;
128
+ distinctId: string;
129
+ groupProperties?: any;
130
+ groups?: any;
131
+ host: string;
132
+ key: string;
133
+ matchValue?: string | boolean;
134
+ personProperties?: any;
135
+ sendFeatureFlagEvents?: boolean;
136
+ },
137
+ any,
138
+ Name
139
+ >;
140
+ getFeatureFlagResult: FunctionReference<
141
+ "action",
142
+ "internal",
143
+ {
144
+ apiKey: string;
145
+ disableGeoip?: boolean;
146
+ distinctId: string;
147
+ groupProperties?: any;
148
+ groups?: any;
149
+ host: string;
150
+ key: string;
151
+ personProperties?: any;
152
+ sendFeatureFlagEvents?: boolean;
153
+ },
154
+ any,
155
+ Name
156
+ >;
157
+ groupIdentify: FunctionReference<
158
+ "action",
159
+ "internal",
160
+ {
161
+ apiKey: string;
162
+ disableGeoip?: boolean;
163
+ distinctId?: string;
164
+ groupKey: string;
165
+ groupType: string;
166
+ host: string;
167
+ properties?: any;
168
+ },
169
+ any,
170
+ Name
171
+ >;
172
+ identify: FunctionReference<
173
+ "action",
174
+ "internal",
175
+ {
176
+ apiKey: string;
177
+ disableGeoip?: boolean;
178
+ distinctId: string;
179
+ host: string;
180
+ properties?: any;
181
+ },
182
+ any,
183
+ Name
184
+ >;
185
+ isFeatureEnabled: FunctionReference<
186
+ "action",
187
+ "internal",
188
+ {
189
+ apiKey: string;
190
+ disableGeoip?: boolean;
191
+ distinctId: string;
192
+ groupProperties?: any;
193
+ groups?: any;
194
+ host: string;
195
+ key: string;
196
+ personProperties?: any;
197
+ sendFeatureFlagEvents?: boolean;
198
+ },
199
+ any,
200
+ Name
201
+ >;
202
+ };
203
+ };
@@ -0,0 +1,60 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Generated data model types.
4
+ *
5
+ * THIS CODE IS AUTOMATICALLY GENERATED.
6
+ *
7
+ * To regenerate, run `npx convex dev`.
8
+ * @module
9
+ */
10
+
11
+ import type {
12
+ DataModelFromSchemaDefinition,
13
+ DocumentByName,
14
+ TableNamesInDataModel,
15
+ SystemTableNames,
16
+ } from "convex/server";
17
+ import type { GenericId } from "convex/values";
18
+ import schema from "../schema.js";
19
+
20
+ /**
21
+ * The names of all of your Convex tables.
22
+ */
23
+ export type TableNames = TableNamesInDataModel<DataModel>;
24
+
25
+ /**
26
+ * The type of a document stored in Convex.
27
+ *
28
+ * @typeParam TableName - A string literal type of the table name (like "users").
29
+ */
30
+ export type Doc<TableName extends TableNames> = DocumentByName<
31
+ DataModel,
32
+ TableName
33
+ >;
34
+
35
+ /**
36
+ * An identifier for a document in Convex.
37
+ *
38
+ * Convex documents are uniquely identified by their `Id`, which is accessible
39
+ * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
40
+ *
41
+ * Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.
42
+ *
43
+ * IDs are just strings at runtime, but this type can be used to distinguish them from other
44
+ * strings when type checking.
45
+ *
46
+ * @typeParam TableName - A string literal type of the table name (like "users").
47
+ */
48
+ export type Id<TableName extends TableNames | SystemTableNames> =
49
+ GenericId<TableName>;
50
+
51
+ /**
52
+ * A type describing your Convex data model.
53
+ *
54
+ * This type includes information about what tables you have, the type of
55
+ * documents stored in those tables, and the indexes defined on them.
56
+ *
57
+ * This type is used to parameterize methods like `queryGeneric` and
58
+ * `mutationGeneric` to make them type-safe.
59
+ */
60
+ export type DataModel = DataModelFromSchemaDefinition<typeof schema>;