mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add enterprise licensing and S3 storage backend
Add the enterprise package with Ed25519 license key validation and feature gating. Enterprise code lives in the public repo under a proprietary license (Cal.com/PostHog model), protected legally, not by code hiding. Implement S3-compatible storage backend as the first enterprise feature. The file-storage module now delegates to either local filesystem or S3 based on STORAGE_MODE env var. Works with AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, and any S3-compatible provider. Workspace files remain local (ephemeral processing). New env vars: STORAGE_MODE, S3_BUCKET, S3_REGION, S3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE, S3_PREFIX, SNAPOTTER_LICENSE_KEY. Tested against MinIO: 10 S3 integration tests + 82 existing tests pass with zero regressions.
This commit is contained in:
@@ -98,6 +98,20 @@ if (!env.COOKIE_SECRET) {
|
||||
|
||||
await initAnalytics();
|
||||
|
||||
// Enterprise features (license-gated)
|
||||
let enterpriseLicense: { org: string; plan: string } | null = null;
|
||||
try {
|
||||
const { initEnterprise } = await import("@snapotter/enterprise");
|
||||
const result = initEnterprise(env.SNAPOTTER_LICENSE_KEY || undefined);
|
||||
if (result.valid && result.license) {
|
||||
enterpriseLicense = result.license;
|
||||
} else if (env.SNAPOTTER_LICENSE_KEY) {
|
||||
console.warn("[WARN] Invalid or expired enterprise license key");
|
||||
}
|
||||
} catch {
|
||||
// Enterprise package not available
|
||||
}
|
||||
|
||||
// Mark any jobs left in processing/queued from a previous unclean shutdown
|
||||
recoverStaleJobs();
|
||||
|
||||
@@ -278,6 +292,9 @@ app.get("/api/v1/admin/health", async (request, reply) => {
|
||||
database: dbOk ? "ok" : "error",
|
||||
queue: { active: 0, pending: 0 },
|
||||
ai: { gpu: isGpuAvailable(), dispatcher: getDispatcherStatus() },
|
||||
enterprise: enterpriseLicense
|
||||
? { active: true, org: enterpriseLicense.org, plan: enterpriseLicense.plan }
|
||||
: { active: false },
|
||||
};
|
||||
});
|
||||
|
||||
@@ -319,6 +336,10 @@ try {
|
||||
`[INFO] Rate limit: ${env.RATE_LIMIT_PER_MIN > 0 ? `${env.RATE_LIMIT_PER_MIN}/min` : "disabled"}`,
|
||||
`[INFO] Upload limit: ${env.MAX_UPLOAD_SIZE_MB > 0 ? `${env.MAX_UPLOAD_SIZE_MB} MB` : "unlimited"}`,
|
||||
`[INFO] Trust proxy: ${env.TRUST_PROXY}`,
|
||||
`[INFO] Storage: ${env.STORAGE_MODE}${env.STORAGE_MODE === "s3" ? ` (${env.S3_BUCKET})` : ""}`,
|
||||
enterpriseLicense
|
||||
? `[INFO] Enterprise license: ${enterpriseLicense.org} (${enterpriseLicense.plan})`
|
||||
: "[INFO] Edition: Community",
|
||||
].join("\n"),
|
||||
);
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user