@@ -3,13 +3,19 @@ import { v } from 'convex/values';
33
44import { internal } from './_generated/api' ;
55import { AnalyticsEvents } from './analyticsEvents' ;
6+ import { getAuthenticatedInstance , requireApiKeyOwnership } from './authHelpers' ;
7+
8+ /**
9+ * List API keys for the authenticated user's instance
10+ */
11+ export const list = query ( {
12+ args : { } ,
13+ handler : async ( ctx ) => {
14+ const instance = await getAuthenticatedInstance ( ctx ) ;
615
7- export const listByUser = query ( {
8- args : { userId : v . id ( 'instances' ) } ,
9- handler : async ( ctx , args ) => {
1016 const keys = await ctx . db
1117 . query ( 'apiKeys' )
12- . withIndex ( 'by_instance' , ( q ) => q . eq ( 'instanceId' , args . userId ) )
18+ . withIndex ( 'by_instance' , ( q ) => q . eq ( 'instanceId' , instance . _id ) )
1319 . collect ( ) ;
1420
1521 return keys . map ( ( k ) => ( {
@@ -24,37 +30,37 @@ export const listByUser = query({
2430 }
2531} ) ;
2632
33+ /**
34+ * Create an API key for the authenticated user's instance
35+ */
2736export const create = mutation ( {
2837 args : {
29- userId : v . id ( 'instances' ) ,
3038 name : v . string ( )
3139 } ,
3240 handler : async ( ctx , args ) => {
33- const instance = await ctx . db . get ( args . userId ) ;
41+ const instance = await getAuthenticatedInstance ( ctx ) ;
3442
3543 const key = generateApiKey ( ) ;
3644 const keyHash = await hashApiKey ( key ) ;
3745 const keyPrefix = key . slice ( 0 , 8 ) ;
3846
3947 const id = await ctx . db . insert ( 'apiKeys' , {
40- instanceId : args . userId ,
48+ instanceId : instance . _id ,
4149 name : args . name ,
4250 keyHash,
4351 keyPrefix,
4452 createdAt : Date . now ( )
4553 } ) ;
4654
47- if ( instance ) {
48- await ctx . scheduler . runAfter ( 0 , internal . analytics . trackEvent , {
49- distinctId : instance . clerkId ,
50- event : AnalyticsEvents . API_KEY_CREATED ,
51- properties : {
52- instanceId : args . userId ,
53- keyId : id ,
54- keyName : args . name
55- }
56- } ) ;
57- }
55+ await ctx . scheduler . runAfter ( 0 , internal . analytics . trackEvent , {
56+ distinctId : instance . clerkId ,
57+ event : AnalyticsEvents . API_KEY_CREATED ,
58+ properties : {
59+ instanceId : instance . _id ,
60+ keyId : id ,
61+ keyName : args . name
62+ }
63+ } ) ;
5864
5965 return { id, key } ;
6066 }
@@ -69,29 +75,32 @@ function generateApiKey(): string {
6975 return result ;
7076}
7177
78+ /**
79+ * Revoke an API key owned by the authenticated user
80+ */
7281export const revoke = mutation ( {
7382 args : { keyId : v . id ( 'apiKeys' ) } ,
7483 handler : async ( ctx , args ) => {
75- const apiKey = await ctx . db . get ( args . keyId ) ;
76- const instance = apiKey ? await ctx . db . get ( apiKey . instanceId ) : null ;
84+ const { apiKey, instance } = await requireApiKeyOwnership ( ctx , args . keyId ) ;
7785
7886 await ctx . db . patch ( args . keyId , {
7987 revokedAt : Date . now ( )
8088 } ) ;
8189
82- if ( instance && apiKey ) {
83- await ctx . scheduler . runAfter ( 0 , internal . analytics . trackEvent , {
84- distinctId : instance . clerkId ,
85- event : AnalyticsEvents . API_KEY_REVOKED ,
86- properties : {
87- instanceId : apiKey . instanceId ,
88- keyId : args . keyId
89- }
90- } ) ;
91- }
90+ await ctx . scheduler . runAfter ( 0 , internal . analytics . trackEvent , {
91+ distinctId : instance . clerkId ,
92+ event : AnalyticsEvents . API_KEY_REVOKED ,
93+ properties : {
94+ instanceId : apiKey . instanceId ,
95+ keyId : args . keyId
96+ }
97+ } ) ;
9298 }
9399} ) ;
94100
101+ /**
102+ * Validate an API key (internal use - no auth required as this validates the key itself)
103+ */
95104export const validate = query ( {
96105 args : { apiKey : v . string ( ) } ,
97106 handler : async ( ctx , args ) => {
@@ -124,6 +133,9 @@ export const validate = query({
124133 }
125134} ) ;
126135
136+ /**
137+ * Touch last used timestamp for an API key (internal use for tracking)
138+ */
127139export const touchLastUsed = mutation ( {
128140 args : { keyId : v . id ( 'apiKeys' ) } ,
129141 handler : async ( ctx , args ) => {
0 commit comments