ahok-skill 1.3.1
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.
- package/.prettierrc +8 -0
- package/Dockerfile +59 -0
- package/RAW_SKILL.md +219 -0
- package/README.md +277 -0
- package/SKILL.md +58 -0
- package/bin/opm.js +268 -0
- package/data/openmemory.sqlite +0 -0
- package/data/openmemory.sqlite-shm +0 -0
- package/data/openmemory.sqlite-wal +0 -0
- package/dist/ai/graph.js +293 -0
- package/dist/ai/mcp.js +397 -0
- package/dist/cli.js +78 -0
- package/dist/core/cfg.js +87 -0
- package/dist/core/db.js +636 -0
- package/dist/core/memory.js +116 -0
- package/dist/core/migrate.js +227 -0
- package/dist/core/models.js +105 -0
- package/dist/core/telemetry.js +57 -0
- package/dist/core/types.js +2 -0
- package/dist/core/vector/postgres.js +52 -0
- package/dist/core/vector/valkey.js +246 -0
- package/dist/core/vector_store.js +2 -0
- package/dist/index.js +44 -0
- package/dist/memory/decay.js +301 -0
- package/dist/memory/embed.js +675 -0
- package/dist/memory/hsg.js +959 -0
- package/dist/memory/reflect.js +131 -0
- package/dist/memory/user_summary.js +99 -0
- package/dist/migrate.js +9 -0
- package/dist/ops/compress.js +255 -0
- package/dist/ops/dynamics.js +189 -0
- package/dist/ops/extract.js +333 -0
- package/dist/ops/ingest.js +214 -0
- package/dist/server/index.js +109 -0
- package/dist/server/middleware/auth.js +137 -0
- package/dist/server/routes/auth.js +186 -0
- package/dist/server/routes/compression.js +108 -0
- package/dist/server/routes/dashboard.js +399 -0
- package/dist/server/routes/docs.js +241 -0
- package/dist/server/routes/dynamics.js +312 -0
- package/dist/server/routes/ide.js +280 -0
- package/dist/server/routes/index.js +33 -0
- package/dist/server/routes/keys.js +132 -0
- package/dist/server/routes/langgraph.js +61 -0
- package/dist/server/routes/memory.js +213 -0
- package/dist/server/routes/sources.js +140 -0
- package/dist/server/routes/system.js +63 -0
- package/dist/server/routes/temporal.js +293 -0
- package/dist/server/routes/users.js +101 -0
- package/dist/server/routes/vercel.js +57 -0
- package/dist/server/server.js +211 -0
- package/dist/server.js +3 -0
- package/dist/sources/base.js +223 -0
- package/dist/sources/github.js +171 -0
- package/dist/sources/google_drive.js +166 -0
- package/dist/sources/google_sheets.js +112 -0
- package/dist/sources/google_slides.js +139 -0
- package/dist/sources/index.js +34 -0
- package/dist/sources/notion.js +165 -0
- package/dist/sources/onedrive.js +143 -0
- package/dist/sources/web_crawler.js +166 -0
- package/dist/temporal_graph/index.js +20 -0
- package/dist/temporal_graph/query.js +240 -0
- package/dist/temporal_graph/store.js +116 -0
- package/dist/temporal_graph/timeline.js +241 -0
- package/dist/temporal_graph/types.js +2 -0
- package/dist/utils/chunking.js +60 -0
- package/dist/utils/index.js +31 -0
- package/dist/utils/keyword.js +94 -0
- package/dist/utils/text.js +120 -0
- package/nodemon.json +7 -0
- package/package.json +50 -0
- package/references/api_reference.md +66 -0
- package/references/examples.md +45 -0
- package/src/ai/graph.ts +363 -0
- package/src/ai/mcp.ts +494 -0
- package/src/cli.ts +94 -0
- package/src/core/cfg.ts +110 -0
- package/src/core/db.ts +1052 -0
- package/src/core/memory.ts +99 -0
- package/src/core/migrate.ts +302 -0
- package/src/core/models.ts +107 -0
- package/src/core/telemetry.ts +47 -0
- package/src/core/types.ts +130 -0
- package/src/core/vector/postgres.ts +61 -0
- package/src/core/vector/valkey.ts +261 -0
- package/src/core/vector_store.ts +9 -0
- package/src/index.ts +5 -0
- package/src/memory/decay.ts +427 -0
- package/src/memory/embed.ts +707 -0
- package/src/memory/hsg.ts +1245 -0
- package/src/memory/reflect.ts +158 -0
- package/src/memory/user_summary.ts +110 -0
- package/src/migrate.ts +8 -0
- package/src/ops/compress.ts +296 -0
- package/src/ops/dynamics.ts +272 -0
- package/src/ops/extract.ts +360 -0
- package/src/ops/ingest.ts +286 -0
- package/src/server/index.ts +159 -0
- package/src/server/middleware/auth.ts +156 -0
- package/src/server/routes/auth.ts +223 -0
- package/src/server/routes/compression.ts +106 -0
- package/src/server/routes/dashboard.ts +420 -0
- package/src/server/routes/docs.ts +380 -0
- package/src/server/routes/dynamics.ts +516 -0
- package/src/server/routes/ide.ts +283 -0
- package/src/server/routes/index.ts +32 -0
- package/src/server/routes/keys.ts +131 -0
- package/src/server/routes/langgraph.ts +71 -0
- package/src/server/routes/memory.ts +440 -0
- package/src/server/routes/sources.ts +111 -0
- package/src/server/routes/system.ts +68 -0
- package/src/server/routes/temporal.ts +335 -0
- package/src/server/routes/users.ts +111 -0
- package/src/server/routes/vercel.ts +55 -0
- package/src/server/server.js +215 -0
- package/src/server.ts +1 -0
- package/src/sources/base.ts +257 -0
- package/src/sources/github.ts +156 -0
- package/src/sources/google_drive.ts +144 -0
- package/src/sources/google_sheets.ts +85 -0
- package/src/sources/google_slides.ts +115 -0
- package/src/sources/index.ts +19 -0
- package/src/sources/notion.ts +148 -0
- package/src/sources/onedrive.ts +131 -0
- package/src/sources/web_crawler.ts +161 -0
- package/src/temporal_graph/index.ts +4 -0
- package/src/temporal_graph/query.ts +299 -0
- package/src/temporal_graph/store.ts +156 -0
- package/src/temporal_graph/timeline.ts +319 -0
- package/src/temporal_graph/types.ts +41 -0
- package/src/utils/chunking.ts +66 -0
- package/src/utils/index.ts +25 -0
- package/src/utils/keyword.ts +137 -0
- package/src/utils/text.ts +115 -0
- package/tests/test_api_workspace_management.ts +413 -0
- package/tests/test_bulk_delete.ts +267 -0
- package/tests/test_omnibus.ts +166 -0
- package/tests/test_workspace_management.ts +278 -0
- package/tests/verify.ts +104 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.authenticate_api_request = authenticate_api_request;
|
|
7
|
+
exports.log_authenticated_request = log_authenticated_request;
|
|
8
|
+
const cfg_1 = require("../../core/cfg");
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
const rate_limit_store = new Map();
|
|
11
|
+
const auth_config = {
|
|
12
|
+
api_key: cfg_1.env.api_key,
|
|
13
|
+
api_key_header: "x-api-key",
|
|
14
|
+
rate_limit_enabled: cfg_1.env.rate_limit_enabled,
|
|
15
|
+
rate_limit_window_ms: cfg_1.env.rate_limit_window_ms,
|
|
16
|
+
rate_limit_max_requests: cfg_1.env.rate_limit_max_requests,
|
|
17
|
+
public_endpoints: [
|
|
18
|
+
"/health",
|
|
19
|
+
"/api/system/health",
|
|
20
|
+
"/api/system/stats",
|
|
21
|
+
"/dashboard/health",
|
|
22
|
+
"/auth",
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
function is_public_endpoint(path) {
|
|
26
|
+
return auth_config.public_endpoints.some((e) => path === e || path.startsWith(e));
|
|
27
|
+
}
|
|
28
|
+
function extract_api_key(req) {
|
|
29
|
+
const x_api_key = req.headers[auth_config.api_key_header];
|
|
30
|
+
if (x_api_key)
|
|
31
|
+
return x_api_key;
|
|
32
|
+
const auth_header = req.headers["authorization"];
|
|
33
|
+
if (auth_header) {
|
|
34
|
+
if (auth_header.startsWith("Bearer "))
|
|
35
|
+
return auth_header.slice(7);
|
|
36
|
+
if (auth_header.startsWith("ApiKey "))
|
|
37
|
+
return auth_header.slice(7);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function validate_api_key(provided, expected) {
|
|
42
|
+
if (!provided || !expected || provided.length !== expected.length)
|
|
43
|
+
return false;
|
|
44
|
+
return crypto_1.default.timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
|
|
45
|
+
}
|
|
46
|
+
function check_rate_limit(client_id) {
|
|
47
|
+
if (!auth_config.rate_limit_enabled)
|
|
48
|
+
return { allowed: true, remaining: -1, reset_time: -1 };
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
const data = rate_limit_store.get(client_id);
|
|
51
|
+
if (!data || now >= data.reset_time) {
|
|
52
|
+
const new_data = {
|
|
53
|
+
count: 1,
|
|
54
|
+
reset_time: now + auth_config.rate_limit_window_ms,
|
|
55
|
+
};
|
|
56
|
+
rate_limit_store.set(client_id, new_data);
|
|
57
|
+
return {
|
|
58
|
+
allowed: true,
|
|
59
|
+
remaining: auth_config.rate_limit_max_requests - 1,
|
|
60
|
+
reset_time: new_data.reset_time,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
data.count++;
|
|
64
|
+
rate_limit_store.set(client_id, data);
|
|
65
|
+
const remaining = auth_config.rate_limit_max_requests - data.count;
|
|
66
|
+
return {
|
|
67
|
+
allowed: data.count <= auth_config.rate_limit_max_requests,
|
|
68
|
+
remaining: Math.max(0, remaining),
|
|
69
|
+
reset_time: data.reset_time,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function get_client_id(req, api_key) {
|
|
73
|
+
if (api_key)
|
|
74
|
+
return crypto_1.default
|
|
75
|
+
.createHash("sha256")
|
|
76
|
+
.update(api_key)
|
|
77
|
+
.digest("hex")
|
|
78
|
+
.slice(0, 16);
|
|
79
|
+
return req.ip || req.connection.remoteAddress || "unknown";
|
|
80
|
+
}
|
|
81
|
+
async function authenticate_api_request(req, res, next) {
|
|
82
|
+
const path = req.path || req.url;
|
|
83
|
+
if (is_public_endpoint(path))
|
|
84
|
+
return next();
|
|
85
|
+
const provided = extract_api_key(req);
|
|
86
|
+
if (!provided) {
|
|
87
|
+
return res.status(401).json({
|
|
88
|
+
error: "authentication_required",
|
|
89
|
+
message: "API key required",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// 1. Check master key
|
|
93
|
+
if (auth_config.api_key && validate_api_key(provided, auth_config.api_key)) {
|
|
94
|
+
req.user = { user_id: "admin", is_admin: true };
|
|
95
|
+
return next();
|
|
96
|
+
}
|
|
97
|
+
// 2. Check database for individual API keys
|
|
98
|
+
try {
|
|
99
|
+
const { q } = require("../../core/db");
|
|
100
|
+
let user = await q.get_user_by_api_key.get(provided);
|
|
101
|
+
if (!user) {
|
|
102
|
+
// Check secondary memory keys
|
|
103
|
+
user = await q.get_user_by_memory_key.get(provided);
|
|
104
|
+
}
|
|
105
|
+
if (user) {
|
|
106
|
+
// Check usage vs capacity
|
|
107
|
+
if (user.memory_usage >= user.memory_capacity && req.method === "POST" && path.includes("/memories")) {
|
|
108
|
+
return res.status(403).json({
|
|
109
|
+
error: "capacity_exceeded",
|
|
110
|
+
message: "Memory capacity reached. Please upgrade your plan.",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
req.user = user;
|
|
114
|
+
if (user.key_id) {
|
|
115
|
+
req.key_id = user.key_id;
|
|
116
|
+
req.key_label = user.key_label;
|
|
117
|
+
}
|
|
118
|
+
return next();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error("[AUTH] Database lookup failed:", err);
|
|
123
|
+
}
|
|
124
|
+
return res.status(403).json({ error: "invalid_api_key" });
|
|
125
|
+
}
|
|
126
|
+
function log_authenticated_request(req, res, next) {
|
|
127
|
+
const key = extract_api_key(req);
|
|
128
|
+
if (key)
|
|
129
|
+
console.log(`[AUTH] ${req.method} ${req.path} [${crypto_1.default.createHash("sha256").update(key).digest("hex").slice(0, 8)}...]`);
|
|
130
|
+
next();
|
|
131
|
+
}
|
|
132
|
+
setInterval(() => {
|
|
133
|
+
const now = Date.now();
|
|
134
|
+
for (const [id, data] of rate_limit_store.entries())
|
|
135
|
+
if (now >= data.reset_time)
|
|
136
|
+
rate_limit_store.delete(id);
|
|
137
|
+
}, 5 * 60 * 1000);
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.auth = void 0;
|
|
7
|
+
const db_1 = require("../../core/db");
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const stripe_1 = __importDefault(require("stripe"));
|
|
10
|
+
const stripe = new stripe_1.default(process.env.STRIPE_SECRET_KEY || "", {
|
|
11
|
+
apiVersion: "2025-01-27.acacia",
|
|
12
|
+
});
|
|
13
|
+
const backend_1 = require("@clerk/backend");
|
|
14
|
+
const clerk = (0, backend_1.createClerkClient)({ secretKey: process.env.CLERK_SECRET_KEY });
|
|
15
|
+
const auth = (app) => {
|
|
16
|
+
// Sync user from Clerk with JWT verification
|
|
17
|
+
app.post("/auth/clerk-sync", async (req, res) => {
|
|
18
|
+
try {
|
|
19
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
20
|
+
if (!token)
|
|
21
|
+
return res.status(401).json({ error: "No token provided" });
|
|
22
|
+
const session = await (0, backend_1.verifyToken)(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
23
|
+
const clerk_id = session.sub;
|
|
24
|
+
const { email } = req.body;
|
|
25
|
+
let user = await db_1.q.get_user_by_clerk_id.get(clerk_id);
|
|
26
|
+
if (!user) {
|
|
27
|
+
// Create new user
|
|
28
|
+
const user_id = crypto_1.default.randomUUID();
|
|
29
|
+
const api_key = `opm_${crypto_1.default.randomBytes(24).toString("hex")}`;
|
|
30
|
+
// Create Stripe customer
|
|
31
|
+
let stripe_customer_id = "";
|
|
32
|
+
try {
|
|
33
|
+
const customer = await stripe.customers.create({
|
|
34
|
+
email,
|
|
35
|
+
metadata: { clerk_id, user_id },
|
|
36
|
+
});
|
|
37
|
+
stripe_customer_id = customer.id;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
console.error("[STRIPE] Customer creation failed:", e);
|
|
41
|
+
}
|
|
42
|
+
await db_1.q.ins_user.run(user_id, clerk_id, api_key, stripe_customer_id, null, // subscription_id
|
|
43
|
+
1000, // default capacity
|
|
44
|
+
0, // current usage
|
|
45
|
+
"", // summary
|
|
46
|
+
0, // reflection_count
|
|
47
|
+
Date.now(), Date.now());
|
|
48
|
+
user = await db_1.q.get_user_by_clerk_id.get(clerk_id);
|
|
49
|
+
}
|
|
50
|
+
else if (!user.stripe_customer_id && email) {
|
|
51
|
+
// Backward compatibility: create Stripe customer for existing user
|
|
52
|
+
try {
|
|
53
|
+
const customer = await stripe.customers.create({
|
|
54
|
+
email,
|
|
55
|
+
metadata: { clerk_id: user.clerk_id, user_id: user.user_id },
|
|
56
|
+
});
|
|
57
|
+
await db_1.q.upd_user_billing.run(user.user_id, customer.id, user.stripe_subscription_id, user.memory_capacity, Date.now());
|
|
58
|
+
user.stripe_customer_id = customer.id;
|
|
59
|
+
console.log(`[STRIPE] Fixed missing customer for ${clerk_id}`);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
console.error("[STRIPE] Customer repair failed:", e);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
res.json(user);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error("[AUTH] Clerk Sync Error:", err);
|
|
69
|
+
res.status(500).json({ error: err.message, stack: err.stack });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// Create Stripe Checkout Session with JWT verification
|
|
73
|
+
app.post("/auth/create-checkout", async (req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
76
|
+
if (!token)
|
|
77
|
+
return res.status(401).json({ error: "No token provided" });
|
|
78
|
+
const clerkSession = await (0, backend_1.verifyToken)(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
79
|
+
const clerk_id = clerkSession.sub;
|
|
80
|
+
const { plan } = req.body;
|
|
81
|
+
const user = await db_1.q.get_user_by_clerk_id.get(clerk_id);
|
|
82
|
+
if (!user)
|
|
83
|
+
return res.status(404).json({ error: "User not found" });
|
|
84
|
+
const priceMap = {
|
|
85
|
+
"pro": 2000, // $20.00
|
|
86
|
+
"enterprise": 10000, // $100.00
|
|
87
|
+
};
|
|
88
|
+
const checkoutOptions = {
|
|
89
|
+
payment_method_types: ["card"],
|
|
90
|
+
line_items: [{
|
|
91
|
+
price_data: {
|
|
92
|
+
currency: "usd",
|
|
93
|
+
product_data: {
|
|
94
|
+
name: `OpenMemory ${plan.toUpperCase()} Plan`,
|
|
95
|
+
},
|
|
96
|
+
unit_amount: priceMap[plan] || 2000,
|
|
97
|
+
recurring: { interval: "month" },
|
|
98
|
+
},
|
|
99
|
+
quantity: 1,
|
|
100
|
+
}],
|
|
101
|
+
mode: "subscription",
|
|
102
|
+
success_url: `${process.env.DASHBOARD_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
|
|
103
|
+
cancel_url: `${process.env.DASHBOARD_URL}/cancel`,
|
|
104
|
+
metadata: { clerk_id, plan },
|
|
105
|
+
};
|
|
106
|
+
if (user.stripe_customer_id) {
|
|
107
|
+
checkoutOptions.customer = user.stripe_customer_id;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Should have been fixed by clerk-sync, but use email as fallback
|
|
111
|
+
const clerkUser = await clerk.users.getUser(clerk_id);
|
|
112
|
+
checkoutOptions.customer_email = clerkUser.emailAddresses[0]?.emailAddress;
|
|
113
|
+
}
|
|
114
|
+
const session = await stripe.checkout.sessions.create(checkoutOptions);
|
|
115
|
+
res.json({ url: session.url });
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error("[STRIPE] Checkout Error:", err);
|
|
119
|
+
res.status(500).json({ error: err.message, stack: err.stack });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
// Create Stripe Customer Portal Session
|
|
123
|
+
app.post("/auth/create-portal", async (req, res) => {
|
|
124
|
+
try {
|
|
125
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
126
|
+
if (!token)
|
|
127
|
+
return res.status(401).json({ error: "No token provided" });
|
|
128
|
+
const clerkSession = await (0, backend_1.verifyToken)(token, { secretKey: process.env.CLERK_SECRET_KEY });
|
|
129
|
+
const clerk_id = clerkSession.sub;
|
|
130
|
+
const user = await db_1.q.get_user_by_clerk_id.get(clerk_id);
|
|
131
|
+
if (!user || !user.stripe_customer_id) {
|
|
132
|
+
return res.status(400).json({ error: "User or customer not found" });
|
|
133
|
+
}
|
|
134
|
+
const session = await stripe.billingPortal.sessions.create({
|
|
135
|
+
customer: user.stripe_customer_id,
|
|
136
|
+
return_url: `${process.env.DASHBOARD_URL}/dashboard`,
|
|
137
|
+
});
|
|
138
|
+
res.json({ url: session.url });
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error("[STRIPE] Portal Error:", err);
|
|
142
|
+
res.status(500).json({ error: err.message });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// Stripe Webhook
|
|
146
|
+
app.post("/auth/stripe-webhook", async (req, res) => {
|
|
147
|
+
const sig = req.headers["stripe-signature"];
|
|
148
|
+
let event;
|
|
149
|
+
try {
|
|
150
|
+
event = stripe.webhooks.constructEvent(req.rawBody || JSON.stringify(req.body), sig, process.env.STRIPE_WEBHOOK_SECRET || "");
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
154
|
+
}
|
|
155
|
+
if (event.type === "checkout.session.completed") {
|
|
156
|
+
const session = event.data.object;
|
|
157
|
+
const clerk_id = session.metadata?.clerk_id;
|
|
158
|
+
const plan = session.metadata?.plan;
|
|
159
|
+
if (clerk_id) {
|
|
160
|
+
const user = await db_1.q.get_user_by_clerk_id.get(clerk_id);
|
|
161
|
+
if (user) {
|
|
162
|
+
const capacityMap = {
|
|
163
|
+
"pro": 50000,
|
|
164
|
+
"enterprise": 1000000,
|
|
165
|
+
};
|
|
166
|
+
const new_capacity = capacityMap[plan] || 50000;
|
|
167
|
+
await db_1.q.upd_user_billing.run(user.user_id, user.stripe_customer_id, session.subscription, new_capacity, Date.now());
|
|
168
|
+
console.log(`[STRIPE] Updated capacity for ${clerk_id} to ${new_capacity}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else if (event.type === "customer.subscription.deleted") {
|
|
173
|
+
const subscription = event.data.object;
|
|
174
|
+
const customer_id = subscription.customer;
|
|
175
|
+
// Downgrade user to free tier
|
|
176
|
+
const user = await db_1.q.get_user_by_stripe_customer_id.get(customer_id);
|
|
177
|
+
if (user) {
|
|
178
|
+
await db_1.q.upd_user_billing.run(user.user_id, user.stripe_customer_id, null, 1000, // back to free tier
|
|
179
|
+
Date.now());
|
|
180
|
+
console.log(`[STRIPE] Downgraded ${user.clerk_id} to free tier`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
res.json({ received: true });
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
exports.auth = auth;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compression = compression;
|
|
4
|
+
const compress_1 = require("../../ops/compress");
|
|
5
|
+
function compression(app) {
|
|
6
|
+
app.post("/api/compression/compress", async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const { text, algorithm } = req.body;
|
|
9
|
+
if (!text)
|
|
10
|
+
return res.status(400).json({ error: "text required" });
|
|
11
|
+
let r;
|
|
12
|
+
if (algorithm &&
|
|
13
|
+
["semantic", "syntactic", "aggressive"].includes(algorithm)) {
|
|
14
|
+
r = compress_1.compressionEngine.compress(text, algorithm);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
r = compress_1.compressionEngine.auto(text);
|
|
18
|
+
}
|
|
19
|
+
res.json({ ok: true, comp: r.comp, m: r.metrics, hash: r.hash });
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
res.status(500).json({ error: e.message });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
app.post("/api/compression/batch", async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const { texts, algorithm = "semantic" } = req.body;
|
|
28
|
+
if (!Array.isArray(texts))
|
|
29
|
+
return res.status(400).json({ error: "texts must be array" });
|
|
30
|
+
if (!["semantic", "syntactic", "aggressive"].includes(algorithm))
|
|
31
|
+
return res.status(400).json({ error: "invalid algo" });
|
|
32
|
+
const r = compress_1.compressionEngine.batch(texts, algorithm);
|
|
33
|
+
res.json({
|
|
34
|
+
ok: true,
|
|
35
|
+
results: r.map((x) => ({
|
|
36
|
+
comp: x.comp,
|
|
37
|
+
m: x.metrics,
|
|
38
|
+
hash: x.hash,
|
|
39
|
+
})),
|
|
40
|
+
total: r.reduce((s, x) => s + x.metrics.saved, 0),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
res.status(500).json({ error: e.message });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
app.post("/api/compression/analyze", async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const { text } = req.body;
|
|
50
|
+
if (!text)
|
|
51
|
+
return res.status(400).json({ error: "text required" });
|
|
52
|
+
const a = compress_1.compressionEngine.analyze(text);
|
|
53
|
+
let best = "semantic";
|
|
54
|
+
let max = 0;
|
|
55
|
+
for (const [algo, m] of Object.entries(a)) {
|
|
56
|
+
const met = m;
|
|
57
|
+
if (met.pct > max) {
|
|
58
|
+
max = met.pct;
|
|
59
|
+
best = algo;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
res.json({
|
|
63
|
+
ok: true,
|
|
64
|
+
analysis: a,
|
|
65
|
+
rec: {
|
|
66
|
+
algo: best,
|
|
67
|
+
save: a[best].pct.toFixed(2) + "%",
|
|
68
|
+
lat: a[best].latency.toFixed(2) + "ms",
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
res.status(500).json({ error: e.message });
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
app.get("/api/compression/stats", async (req, res) => {
|
|
77
|
+
try {
|
|
78
|
+
const s = compress_1.compressionEngine.getStats();
|
|
79
|
+
res.json({
|
|
80
|
+
ok: true,
|
|
81
|
+
stats: {
|
|
82
|
+
...s,
|
|
83
|
+
avgRatio: (s.avgRatio * 100).toFixed(2) + "%",
|
|
84
|
+
totalPct: s.ogTok > 0
|
|
85
|
+
? ((s.saved / s.ogTok) * 100).toFixed(2) + "%"
|
|
86
|
+
: "0%",
|
|
87
|
+
lat: s.latency.toFixed(2) + "ms",
|
|
88
|
+
avgLat: s.total > 0
|
|
89
|
+
? (s.latency / s.total).toFixed(2) + "ms"
|
|
90
|
+
: "0ms",
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
res.status(500).json({ error: e.message });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
app.post("/api/compression/reset", async (req, res) => {
|
|
99
|
+
try {
|
|
100
|
+
compress_1.compressionEngine.reset();
|
|
101
|
+
compress_1.compressionEngine.clear();
|
|
102
|
+
res.json({ ok: true, msg: "reset done" });
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
res.status(500).json({ error: e.message });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|