CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
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 | import { join } from "path";
export const config = {
get port() {
return Number(process.env.PORT || 3000);
},
get databaseUrl() {
return process.env.DATABASE_URL || "";
},
get gitReposPath() {
return process.env.GIT_REPOS_PATH || join(process.cwd(), "repos");
},
get gatetestUrl() {
return process.env.GATETEST_URL || "https://gatetest.ai/api/events/push";
},
get gatetestApiKey() {
return process.env.GATETEST_API_KEY || "";
},
get crontechDeployUrl() {
return (
process.env.CRONTECH_DEPLOY_URL ||
"https://crontech.ai/api/hooks/gluecron/push"
);
},
/**
* Bearer token sent on outbound deploy webhook to Crontech's
* `POST /api/hooks/gluecron/push` endpoint. Default empty → header is
* omitted and Crontech will reject with 401 (treated as a failed deploy).
*/
get gluecronWebhookSecret() {
return process.env.GLUECRON_WEBHOOK_SECRET || "";
},
get anthropicApiKey() {
return process.env.ANTHROPIC_API_KEY || "";
},
/** HMAC secret used to verify inbound GateTest callback signatures. */
get gatetestCallbackSecret() {
return process.env.GATETEST_CALLBACK_SECRET || "";
},
/** Shared HMAC secret for signing outbound GateTest payloads. */
get gatetestHmacSecret() {
return process.env.GATETEST_HMAC_SECRET || "";
},
/** Bearer token expected on inbound Crontech deploy-event webhooks. */
get crontechEventToken() {
return process.env.CRONTECH_EVENT_TOKEN || "";
},
/** Voyage AI API key for semantic (embedding) code search. */
get voyageApiKey() {
return process.env.VOYAGE_API_KEY || "";
},
/** Email provider: "log" (dev, writes to stderr) or "resend" (HTTPS). */
get emailProvider() {
const v = (process.env.EMAIL_PROVIDER || "log").toLowerCase();
return v === "resend" ? "resend" : "log";
},
/** "From" address for outbound email. */
get emailFrom() {
return process.env.EMAIL_FROM || "gluecron <no-reply@gluecron.local>";
},
/** Resend API key (only used when EMAIL_PROVIDER=resend). */
get resendApiKey() {
return process.env.RESEND_API_KEY || "";
},
/** Canonical base URL for outbound links in emails + webhooks. */
get appBaseUrl() {
return (process.env.APP_BASE_URL || "http://localhost:3000").replace(
/\/+$/,
""
);
},
/**
* WebAuthn relying-party ID (domain only, no scheme/port). Derived from
* appBaseUrl unless overridden. Passkeys issued for one RP ID can't be
* replayed against another, so this must be stable.
*/
get webauthnRpId() {
if (process.env.WEBAUTHN_RP_ID) return process.env.WEBAUTHN_RP_ID;
try {
return new URL(this.appBaseUrl).hostname;
} catch {
return "localhost";
}
},
/** WebAuthn expected origin (must include scheme + port). */
get webauthnOrigin() {
return process.env.WEBAUTHN_ORIGIN || this.appBaseUrl;
},
/** Human-facing RP name shown by the browser. */
get webauthnRpName() {
return process.env.WEBAUTHN_RP_NAME || "gluecron";
},
};
|