+1
-36
packages/functions/src/extension-import.ts
+1
-36
packages/functions/src/extension-import.ts
···
1
1
import type { Handler, HandlerEvent } from '@netlify/functions';
2
2
import type { ExtensionImportRequest, ExtensionImportResponse } from '@atlast/shared';
3
3
import { z } from 'zod';
4
-
import crypto from 'crypto';
4
+
import { storeImport } from './utils/import-store.js';
5
5
6
6
/**
7
7
* Validation schema for extension import request
···
16
16
sourceUrl: z.string().url()
17
17
})
18
18
});
19
-
20
-
/**
21
-
* Simple in-memory store for extension imports
22
-
* TODO: Move to database for production
23
-
*/
24
-
const importStore = new Map<string, ExtensionImportRequest>();
25
-
26
-
/**
27
-
* Generate a random import ID
28
-
*/
29
-
function generateImportId(): string {
30
-
return crypto.randomBytes(16).toString('hex');
31
-
}
32
-
33
-
/**
34
-
* Store import data and return import ID
35
-
*/
36
-
function storeImport(data: ExtensionImportRequest): string {
37
-
const importId = generateImportId();
38
-
importStore.set(importId, data);
39
-
40
-
// Auto-expire after 1 hour
41
-
setTimeout(() => {
42
-
importStore.delete(importId);
43
-
}, 60 * 60 * 1000);
44
-
45
-
return importId;
46
-
}
47
19
48
20
/**
49
21
* Extension import endpoint
···
137
109
}
138
110
};
139
111
140
-
/**
141
-
* Get import endpoint (helper for import page)
142
-
* GET /extension-import/:id
143
-
*/
144
-
export function getImport(importId: string): ExtensionImportRequest | null {
145
-
return importStore.get(importId) || null;
146
-
}
+3
-8
packages/functions/src/get-extension-import.ts
+3
-8
packages/functions/src/get-extension-import.ts
···
1
1
import type { Handler, HandlerEvent } from '@netlify/functions';
2
2
import type { ExtensionImportRequest } from '@atlast/shared';
3
-
4
-
/**
5
-
* Import store (shared with extension-import.ts)
6
-
* In production, this would be a database query
7
-
*/
8
-
const importStore = new Map<string, ExtensionImportRequest>();
3
+
import { getImport } from './utils/import-store.js';
9
4
10
5
/**
11
6
* Get extension import by ID
···
49
44
};
50
45
}
51
46
52
-
// Get import data
53
-
const importData = importStore.get(importId);
47
+
// Get import data from shared store
48
+
const importData = getImport(importId);
54
49
55
50
if (!importData) {
56
51
return {
+70
packages/functions/src/utils/import-store.ts
+70
packages/functions/src/utils/import-store.ts
···
1
+
import type { ExtensionImportRequest } from '@atlast/shared';
2
+
import crypto from 'crypto';
3
+
4
+
/**
5
+
* Shared in-memory store for extension imports
6
+
* This is shared between extension-import.ts and get-extension-import.ts
7
+
*
8
+
* NOTE: In-memory storage works for development but will NOT work reliably
9
+
* in production serverless environments where functions are stateless and
10
+
* can run on different instances.
11
+
*
12
+
* For production, replace this with:
13
+
* - Database (PostgreSQL/Neon)
14
+
* - Redis/Upstash
15
+
* - Netlify Blobs
16
+
*/
17
+
const importStore = new Map<string, ExtensionImportRequest>();
18
+
19
+
/**
20
+
* Generate a random import ID
21
+
*/
22
+
export function generateImportId(): string {
23
+
return crypto.randomBytes(16).toString('hex');
24
+
}
25
+
26
+
/**
27
+
* Store import data and return import ID
28
+
*/
29
+
export function storeImport(data: ExtensionImportRequest): string {
30
+
const importId = generateImportId();
31
+
importStore.set(importId, data);
32
+
33
+
console.log(`[ImportStore] Stored import ${importId} with ${data.usernames.length} usernames`);
34
+
35
+
// Auto-expire after 1 hour
36
+
setTimeout(() => {
37
+
importStore.delete(importId);
38
+
console.log(`[ImportStore] Expired import ${importId}`);
39
+
}, 60 * 60 * 1000);
40
+
41
+
return importId;
42
+
}
43
+
44
+
/**
45
+
* Get import data by ID
46
+
*/
47
+
export function getImport(importId: string): ExtensionImportRequest | null {
48
+
const data = importStore.get(importId) || null;
49
+
console.log(`[ImportStore] Get import ${importId}: ${data ? 'found' : 'not found'}`);
50
+
return data;
51
+
}
52
+
53
+
/**
54
+
* Delete import data by ID
55
+
*/
56
+
export function deleteImport(importId: string): boolean {
57
+
const result = importStore.delete(importId);
58
+
console.log(`[ImportStore] Delete import ${importId}: ${result ? 'success' : 'not found'}`);
59
+
return result;
60
+
}
61
+
62
+
/**
63
+
* Get store stats (for debugging)
64
+
*/
65
+
export function getStoreStats(): { count: number; ids: string[] } {
66
+
return {
67
+
count: importStore.size,
68
+
ids: Array.from(importStore.keys())
69
+
};
70
+
}