1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import * as uuid from "https://deno.land/std/uuid/mod.ts";
import { blob } from "https://esm.town/v/std/blob";
import { getPolicy } from "https://esm.town/v/xkonti/memoryApiPolicy";
import { Hono } from "npm:hono@3";
export const handleMemoryApiRequest = async (
req: Request,
apiName: string,
contactEmail: string,
lastPolicyUpdate: string,
blobKeyPrefix: string,
apiKeyPrefix: string,
) => {
// ==== HELPERS ====
const getMemoriesKey = (key: string): string => {
return `${blobKeyPrefix}${key}`;
};
const getMemories = async (key: string) => {
return await blob.getJSON(getMemoriesKey(key), []);
};
const setMemories = async (memories: any, key: string) => {
await blob.setJSON(getMemoriesKey(key), memories);
};
const verifyRequest = (c): { memoriesKey: string; error: any } => {
// Verify API key coming as a Bearer header
const authHeader = c.req.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Basic ")) {
console.error("Missing or invalid authorization header");
return { memoriesKey: "", error: c.text("Unauthorized", 401) };
}
// Extract and decode the base64 encoded credentials
const base64Credentials = authHeader.split(" ")[1];
const credentials = atob(base64Credentials);
// Split into user and password
const [key, token] = credentials.split(":");
if (key == null || key === "") {
console.error("No memory key in authorization header");
return { memoriesKey: "", error: c.text("Forbidden", 403) };
}
const expectedKey = Deno.env.get(apiKeyPrefix + key) ?? null;
if (token !== expectedKey) {
console.error("Invalid API KEY header");
return { memoriesKey: "", error: c.text("Forbidden", 403) };
}
return { memoriesKey: key, error: null };
};
// API
const app = new Hono();
// GET ALL MEMORIES
app.get("/memory", async (c) => {
const { memoriesKey, error } = verifyRequest(c);
if (error != null) return error;
// Get all memories and filter out detailed descriptions
const memories = (await getMemories(memoriesKey))
.map(memory => ({
id: memory.id,
name: memory.name,
summary: memory.summary ?? "Missing summary",
reason: memory.reason,
}));
return c.json({
memories,
});
});
// GET SPECIFIC MEMORIES BY IDS
app.get("/memory/specific", async (c) => {
const { memoriesKey, error } = verifyRequest(c);
if (error != null) return error;
// Extract the IDs from the query parameter
const idsQuery = c.req.query("ids");
if (!idsQuery) {
return c.text("Bad Request: No IDs provided", 400);
}
// Split the IDs and validate them
const ids = idsQuery.split(",");
if (ids.length === 0) {
return c.text("Bad Request: Invalid IDs format", 400);
}
// Get the current list of Memories
const memories = await getMemories(memoriesKey);
// Filter for memories with the given IDs
const requestedMemories = memories.filter(memory => ids.includes(memory.id));
// Check if any memories were found
if (requestedMemories.length === 0) {
return c.text("No memories found with the provided IDs", 404);