const std = @import("std"); var public_url_value: []const u8 = "http://localhost:2583"; var server_did_value: []const u8 = "did:web:localhost"; var plc_directory_value: []const u8 = "https://plc.directory"; var plc_rotation_key_value: ?[]const u8 = null; var recovery_did_key_value: ?[]const u8 = null; var mail_provider_value: MailProvider = .comail; var resend_api_key_value: ?[]const u8 = null; var comail_api_key_value: ?[]const u8 = null; var comail_did_value: ?[]const u8 = null; var email_from_value: ?[]const u8 = null; var blob_upload_limit_value: usize = 100_000_000; var blobstore_path_value: []const u8 = "dev/blobs"; var handle_domains_value: []const u8 = ".test"; var crawlers_value: []const u8 = "https://bsky.network,https://vsky.network"; var max_concurrent_repo_exports_value: usize = 4; var proxy_service_did_value: []const u8 = "did:web:api.bsky.app"; var proxy_service_id_value: []const u8 = "bsky_appview"; var proxy_service_url_value: []const u8 = "https://api.bsky.app"; var jwt_secret_value: []const u8 = "zds-local-development-jwt-secret-change-me"; var dpop_secret_value: ?[]const u8 = null; var admin_token_value: ?[]const u8 = null; var invite_required_value: bool = false; var permissioned_data_value: bool = false; var dev_tools_value: bool = false; var log_level_value: LogLevel = .info; pub const LogLevel = enum(u2) { err = 0, info = 1, debug = 2, }; pub const MailProvider = enum { comail, resend, }; pub fn publicUrl() []const u8 { return public_url_value; } pub fn serverDid() []const u8 { return server_did_value; } pub fn plcDirectory() []const u8 { return plc_directory_value; } pub fn plcRotationKey() ?[]const u8 { return plc_rotation_key_value; } pub fn recoveryDidKey() ?[]const u8 { return recovery_did_key_value; } pub fn mailProvider() MailProvider { return mail_provider_value; } pub fn resendApiKey() ?[]const u8 { return resend_api_key_value; } pub fn comailApiKey() ?[]const u8 { return comail_api_key_value; } pub fn comailDid() ?[]const u8 { return comail_did_value; } pub fn emailFrom() ?[]const u8 { return email_from_value; } pub fn blobUploadLimit() usize { return blob_upload_limit_value; } pub fn blobstorePath() []const u8 { return blobstore_path_value; } pub fn handleDomains() []const u8 { return handle_domains_value; } pub fn crawlers() []const u8 { return crawlers_value; } pub fn maxConcurrentRepoExports() usize { return max_concurrent_repo_exports_value; } pub fn proxyServiceDid() []const u8 { return proxy_service_did_value; } pub fn proxyServiceId() []const u8 { return proxy_service_id_value; } pub fn proxyServiceUrl() []const u8 { return proxy_service_url_value; } pub fn jwtSecret() []const u8 { return jwt_secret_value; } pub fn dpopSecret() []const u8 { return dpop_secret_value orelse jwt_secret_value; } pub fn adminToken() ?[]const u8 { return admin_token_value; } pub fn inviteRequired() bool { return invite_required_value; } pub fn permissionedData() bool { return permissioned_data_value; } pub fn devTools() bool { return dev_tools_value; } pub fn logLevel() LogLevel { return log_level_value; } pub fn logEnabled(level: LogLevel) bool { return @intFromEnum(level) <= @intFromEnum(log_level_value); } pub fn setPublicUrl(value: []const u8) void { public_url_value = trimTrailingSlash(value); } pub fn setServerDid(value: []const u8) void { server_did_value = value; } pub fn setPlcDirectory(value: []const u8) void { plc_directory_value = trimTrailingSlash(value); } pub fn setPlcRotationKey(value: ?[]const u8) void { plc_rotation_key_value = value; } pub fn setRecoveryDidKey(value: ?[]const u8) void { recovery_did_key_value = value; } pub fn setMailProvider(value: MailProvider) void { mail_provider_value = value; } pub fn setResendApiKey(value: ?[]const u8) void { resend_api_key_value = value; } pub fn setComailApiKey(value: ?[]const u8) void { comail_api_key_value = value; } pub fn setComailDid(value: ?[]const u8) void { comail_did_value = value; } pub fn setEmailFrom(value: ?[]const u8) void { email_from_value = value; } pub fn setBlobUploadLimit(value: usize) void { blob_upload_limit_value = value; } pub fn setBlobstorePath(value: []const u8) void { blobstore_path_value = trimTrailingSlash(value); } pub fn setHandleDomains(value: []const u8) void { handle_domains_value = value; } pub fn setCrawlers(value: []const u8) void { crawlers_value = value; } pub fn setMaxConcurrentRepoExports(value: usize) void { max_concurrent_repo_exports_value = value; } pub fn setProxyServiceDid(value: []const u8) void { proxy_service_did_value = value; } pub fn setProxyServiceId(value: []const u8) void { proxy_service_id_value = value; } pub fn setProxyServiceUrl(value: []const u8) void { proxy_service_url_value = trimTrailingSlash(value); } pub fn setJwtSecret(value: []const u8) void { jwt_secret_value = value; } pub fn setDpopSecret(value: ?[]const u8) void { dpop_secret_value = value; } pub fn setAdminToken(value: ?[]const u8) void { admin_token_value = value; } pub fn setInviteRequired(value: bool) void { invite_required_value = value; } pub fn setPermissionedData(value: bool) void { permissioned_data_value = value; } pub fn setDevTools(value: bool) void { dev_tools_value = value; } pub fn setLogLevel(value: LogLevel) void { log_level_value = value; } pub fn parseLogLevel(value: []const u8) ?LogLevel { if (std.ascii.eqlIgnoreCase(value, "error")) return .err; if (std.ascii.eqlIgnoreCase(value, "err")) return .err; if (std.ascii.eqlIgnoreCase(value, "info")) return .info; if (std.ascii.eqlIgnoreCase(value, "debug")) return .debug; return null; } pub fn parseMailProvider(value: []const u8) ?MailProvider { if (std.ascii.eqlIgnoreCase(value, "comail")) return .comail; if (std.ascii.eqlIgnoreCase(value, "resend")) return .resend; return null; } fn trimTrailingSlash(value: []const u8) []const u8 { if (value.len > 1 and value[value.len - 1] == '/') return value[0 .. value.len - 1]; return value; } test "trims public URL slash" { const before = publicUrl(); defer setPublicUrl(before); setPublicUrl("https://example.com/"); try std.testing.expectEqualStrings("https://example.com", publicUrl()); } test "trims configured proxy service URL slash" { const before = proxyServiceUrl(); defer setProxyServiceUrl(before); setProxyServiceUrl("https://api.example.com/"); try std.testing.expectEqualStrings("https://api.example.com", proxyServiceUrl()); }