11/**
22 * GitMem Pro Deactivation
33 *
4- * Removes api_key, supabase_url, supabase_key, openrouter_key from config.json.
5- * Deletes license-cache.json.
4+ * 1. Calls gitmem_deactivate_device RPC to remove this device server-side
5+ * 2. Removes api_key, supabase_url, supabase_key, openrouter_key from config.json
6+ * 3. Deletes license-cache.json
67 * Does NOT remove .gitmem/ directory or local data.
78 */
89
910import * as fs from "fs" ;
1011import * as path from "path" ;
11- import { getGitmemDir } from "../services/gitmem-dir.js" ;
12- import { clearLicenseCache } from "../services/license.js" ;
12+ import { getGitmemDir , getInstallId } from "../services/gitmem-dir.js" ;
13+ import {
14+ clearLicenseCache ,
15+ getLicenseKey ,
16+ getValidationUrl ,
17+ } from "../services/license.js" ;
18+
19+ // Same infra endpoint as validation — just different RPC
20+ const DEACTIVATION_URL =
21+ getValidationUrl ( ) . replace ( "gitmem_validate_license" , "gitmem_deactivate_device" ) ;
22+ const VALIDATION_ANON_KEY =
23+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNqcHR4eWV6dXhkaWludWZncnJtIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjYxODY3MDMsImV4cCI6MjA4MTc2MjcwM30.L0oZy3LYCMikmZ15IUU5DnfJmucM37DJ14nUkM3AreY" ;
24+
25+ async function deactivateDeviceRemote (
26+ apiKey : string ,
27+ installId : string ,
28+ ) : Promise < { success : boolean ; message : string } > {
29+ try {
30+ const controller = new AbortController ( ) ;
31+ const timeout = setTimeout ( ( ) => controller . abort ( ) , 10000 ) ;
32+
33+ const response = await fetch ( DEACTIVATION_URL , {
34+ method : "POST" ,
35+ headers : {
36+ "Content-Type" : "application/json" ,
37+ apikey : VALIDATION_ANON_KEY ,
38+ Authorization : `Bearer ${ VALIDATION_ANON_KEY } ` ,
39+ } ,
40+ body : JSON . stringify ( { p_api_key : apiKey , p_install_id : installId } ) ,
41+ signal : controller . signal ,
42+ } ) ;
43+
44+ clearTimeout ( timeout ) ;
45+
46+ if ( ! response . ok ) {
47+ return { success : false , message : `HTTP ${ response . status } ` } ;
48+ }
49+
50+ const rows = ( await response . json ( ) ) as { success : boolean ; message : string } [ ] ;
51+ const data = Array . isArray ( rows ) ? rows [ 0 ] : rows ;
52+ return data || { success : false , message : "Empty response" } ;
53+ } catch ( err : unknown ) {
54+ const message = err instanceof Error ? err . message : "Unknown error" ;
55+ return { success : false , message : `Network error: ${ message } ` } ;
56+ }
57+ }
1358
1459export async function main ( _args : string [ ] ) : Promise < void > {
1560 const gitmemDir = getGitmemDir ( ) ;
@@ -28,9 +73,22 @@ export async function main(_args: string[]): Promise<void> {
2873 process . exit ( 1 ) ;
2974 }
3075
31- const hadKey = ! ! config . api_key ;
76+ const apiKey = getLicenseKey ( ) ;
77+ const installId = getInstallId ( ) ;
78+ const hadKey = ! ! apiKey ;
79+
80+ // Step 1: Remove device server-side (if we have both key and install_id)
81+ if ( apiKey && installId ) {
82+ const result = await deactivateDeviceRemote ( apiKey , installId ) ;
83+ if ( result . success ) {
84+ console . log ( ` ✓ ${ result . message } ` ) ;
85+ } else {
86+ console . log ( ` ⚠ Server deactivation failed: ${ result . message } ` ) ;
87+ console . log ( " Local credentials will still be removed." ) ;
88+ }
89+ }
3290
33- // Remove Pro credentials
91+ // Step 2: Remove Pro credentials from config
3492 delete config . api_key ;
3593 delete config . supabase_url ;
3694 delete config . supabase_key ;
@@ -39,11 +97,12 @@ export async function main(_args: string[]): Promise<void> {
3997 // Write back config (preserving project, install_id, feedback_enabled)
4098 fs . writeFileSync ( configPath , JSON . stringify ( config , null , 2 ) ) ;
4199
42- // Clear license cache
100+ // Step 3: Clear license cache
43101 clearLicenseCache ( ) ;
44102
45103 if ( hadKey ) {
46- console . log ( "Pro tier deactivated." ) ;
104+ console . log ( "\nPro tier deactivated." ) ;
105+ console . log ( " - Device removed from license server" ) ;
47106 console . log ( " - License key removed from config.json" ) ;
48107 console . log ( " - Supabase and OpenRouter credentials removed" ) ;
49108 console . log ( " - License cache cleared" ) ;
0 commit comments