← back to jra3__mulm

Function bodies 451 total

All specs Real LLM only Function bodies
updateCredentialCounter function · typescript · L91-L103 (13 LOC)
src/db/webauthn.ts
export async function updateCredentialCounter(
  credentialId: string,
  newCounter: number
): Promise<void> {
  await updateOne(
    "webauthn_credentials",
    { credential_id: credentialId },
    {
      counter: newCounter,
      last_used_on: new Date().toISOString(),
    }
  );
}
saveChallenge function · typescript · L124-L137 (14 LOC)
src/db/webauthn.ts
export async function saveChallenge(
  challenge: string,
  purpose: "registration" | "authentication",
  memberId?: number
): Promise<void> {
  const expiresOn = new Date(Date.now() + 5 * 60 * 1000); // 5 minutes

  await insertOne("webauthn_challenges", {
    challenge,
    member_id: memberId || null,
    purpose,
    expires_on: expiresOn.toISOString(),
  });
}
getChallenge function · typescript · L142-L156 (15 LOC)
src/db/webauthn.ts
export async function getChallenge(challenge: string): Promise<WebAuthnChallenge | null> {
  const rows = await query<WebAuthnChallenge>(
    'SELECT * FROM webauthn_challenges WHERE challenge = ? AND expires_on > datetime("now")',
    [challenge]
  );

  const challengeData = rows[0] || null;

  // Delete challenge after retrieval (single-use)
  if (challengeData) {
    await deleteOne("webauthn_challenges", { challenge });
  }

  return challengeData;
}
deleteExpiredChallenges function · typescript · L161-L173 (13 LOC)
src/db/webauthn.ts
export async function deleteExpiredChallenges(): Promise<number> {
  const conn = writeConn;
  const stmt = await conn.prepare(
    'DELETE FROM webauthn_challenges WHERE expires_on <= datetime("now")'
  );

  try {
    const result = await stmt.run();
    return result.changes || 0;
  } finally {
    await stmt.finalize();
  }
}
formatCollectionEntry function · typescript · L184-L200 (17 LOC)
src/forms/collection.ts
export function formatCollectionEntry(entry: {
  quantity: number;
  acquired_date: string;
  removed_date?: string | null;
}): string {
  const parts = [`Qty: ${entry.quantity}`];

  if (entry.acquired_date) {
    parts.push(`Acquired: ${new Date(entry.acquired_date).toLocaleDateString()}`);
  }

  if (entry.removed_date) {
    parts.push(`Removed: ${new Date(entry.removed_date).toLocaleDateString()}`);
  }

  return parts.join(" • ");
}
canEditCollection function · typescript · L205-L211 (7 LOC)
src/forms/collection.ts
export function canEditCollection(
  entry: { member_id: number },
  viewer: { id: number; is_admin?: boolean } | null
): boolean {
  if (!viewer) return false;
  return entry.member_id === viewer.id || Boolean(viewer.is_admin);
}
getVisibilityFilter function · typescript · L216-L221 (6 LOC)
src/forms/collection.ts
export function getVisibilityFilter(
  memberId: number,
  viewerId: number | null
): "all" | "public" {
  return memberId === viewerId ? "all" : "public";
}
All rows scored by the Repobility analyzer (https://repobility.com)
formBoolean function · typescript · L12-L23 (12 LOC)
src/forms/formBoolean.ts
export function formBoolean() {
  return z.preprocess((val) => {
    // Handle undefined (field not in form)
    if (val === undefined) return false;
    // If array (hidden + checkbox both sent), take last value
    if (Array.isArray(val)) {
      return val[val.length - 1] === "1";
    }
    // If string
    return val === "1";
  }, z.boolean());
}
getBapFormTitle function · typescript · L19-L30 (12 LOC)
src/forms/submission.ts
export function getBapFormTitle(selectedType: string) {
  switch (selectedType) {
    default:
    case "Fish":
    case "Invert":
      return "Breeder Awards Submission";
    case "Plant":
      return "Horticultural Awards Submission";
    case "Coral":
      return "Coral Awards Submission";
  }
}
validateFormResult function · typescript · L3-L16 (14 LOC)
src/forms/utils.ts
export function validateFormResult<T>(
  parsed: z.SafeParseReturnType<unknown, T>,
  errors: Map<string, string>,
  onError?: () => void
): parsed is z.SafeParseSuccess<T> {
  if (parsed.success) {
    return true;
  }
  parsed.error.issues.forEach((issue) => {
    errors.set(String(issue.path[0]), issue.message);
  });
  onError?.();
  return false;
}
extractValid function · typescript · L18-L37 (20 LOC)
src/forms/utils.ts
export function extractValid<T extends z.ZodRawShape>(
  schema: z.ZodObject<T>,
  data: unknown
): Partial<z.infer<typeof schema>> {
  const result: Partial<z.infer<typeof schema>> = {};

  for (const key in schema.shape) {
    const subSchema = schema.shape[key];
    const value =
      data && typeof data === "object" && key in data
        ? (data as Record<string, unknown>)[key]
        : undefined;
    const parsed = subSchema.safeParse(value);
    if (parsed.success) {
      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
      result[key] = parsed.data;
    }
  }
  return result;
}
validateQueryWithFallback function · typescript · L103-L112 (10 LOC)
src/forms/utils.ts
export function validateQueryWithFallback<T extends z.ZodRawShape>(
  schema: z.ZodObject<T>,
  query: Record<string, unknown>,
  logContext?: string
): {
  success: boolean;
  data: z.infer<typeof schema>;
  errors: string[];
  isPartial: boolean;
} {
IntegrationAPIError.constructor method · typescript · L30-L38 (9 LOC)
src/integrations/base-integration-client.ts
  constructor(
    message: string,
    public serviceName: string,
    public statusCode?: number,
    public response?: unknown
  ) {
    super(message);
    this.name = "IntegrationAPIError";
  }
BaseIntegrationClient.logInit method · typescript · L66-L72 (7 LOC)
src/integrations/base-integration-client.ts
  protected logInit(): void {
    if (!this.config.enabled) {
      logger.info(`${this.serviceName} integration is disabled`);
    } else {
      logger.info(`${this.serviceName} integration client initialized`);
    }
  }
BaseIntegrationClient.enforceRateLimit method · typescript · L84-L95 (12 LOC)
src/integrations/base-integration-client.ts
  protected async enforceRateLimit(): Promise<void> {
    const now = Date.now();
    const timeSinceLastRequest = now - this.lastRequestTime;

    if (timeSinceLastRequest < this.config.rateLimitMs) {
      const waitTime = this.config.rateLimitMs - timeSinceLastRequest;
      logger.info(`${this.serviceName} rate limiting: waiting ${waitTime}ms`);
      await delay(waitTime);
    }

    this.lastRequestTime = Date.now();
  }
Source: Repobility analyzer · https://repobility.com
BaseIntegrationClient.get method · typescript · L100-L205 (106 LOC)
src/integrations/base-integration-client.ts
  protected async get<T>(
    endpoint: string,
    queryParams?: Record<string, string | number | boolean>,
    retryCount = 0
  ): Promise<T | null> {
    await this.enforceRateLimit();

    // Build URL with query parameters
    let url = `${this.config.baseUrl}${endpoint}`;
    if (queryParams) {
      const params = new URLSearchParams();
      for (const [key, value] of Object.entries(queryParams)) {
        params.append(key, String(value));
      }
      url += `?${params.toString()}`;
    }

    logger.info(`${this.serviceName} API request: ${endpoint}`);

    try {
      const controller = new AbortController();
      const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);

      const response = await fetch(url, {
        signal: controller.signal,
        headers: {
          Accept: "application/json",
          ...this.config.headers,
        },
      });

      clearTimeout(timeout);

      // Handle different status codes
      if (response.status =
FishBaseClient.constructor method · typescript · L81-L103 (23 LOC)
src/integrations/fishbase.ts
  constructor(clientConfig?: Partial<IntegrationClientConfig>) {
    const defaultConfig = config.fishbase;

    if (!defaultConfig) {
      throw new Error("FishBase configuration not found in config.json");
    }

    // Map config field names to match IntegrationClientConfig
    const integrationConfig: IntegrationClientConfig = {
      baseUrl: defaultConfig.baseUrl,
      rateLimitMs: defaultConfig.rateLimitMs,
      maxRetries: defaultConfig.maxRetries,
      timeoutMs: defaultConfig.timeoutMs,
      enabled: defaultConfig.enableSync, // Map enableSync to enabled
    };

    super({
      ...integrationConfig,
      ...clientConfig,
    });

    this.logInit();
  }
FishBaseClient.getSpecies method · typescript · L112-L140 (29 LOC)
src/integrations/fishbase.ts
  async getSpecies(genus: string, species: string): Promise<FishBaseSpecies | null> {
    if (!this.isEnabled()) {
      logger.warn("FishBase integration is disabled");
      return null;
    }

    try {
      const response = await this.get<FishBaseSpeciesResponse>("/species", {
        genus,
        species,
      });

      if (!response || response.error) {
        logger.warn(`FishBase API error: ${response?.error || "Unknown error"}`);
        return null;
      }

      if (response.count === 0 || response.data.length === 0) {
        logger.info(`Species not found in FishBase: ${genus} ${species}`);
        return null;
      }

      // Return the first match (should only be one for exact genus/species match)
      return response.data[0];
    } catch (error) {
      logger.error(`Failed to get FishBase species data for ${genus} ${species}`, error);
      return null;
    }
  }
FishBaseClient.getExternalData method · typescript · L149-L189 (41 LOC)
src/integrations/fishbase.ts
  async getExternalData(genus: string, species: string): Promise<FishBaseResult | null> {
    const speciesData = await this.getSpecies(genus, species);

    if (!speciesData) {
      return null;
    }

    // Construct FishBase URL from SpecCode
    const fishbaseUrl = `https://www.fishbase.se/summary/${speciesData.SpecCode}`;

    // Collect image URLs from various fields
    const imageUrls: string[] = [];

    // Helper function to add image URLs
    const addImageUrl = (filename: string | null) => {
      if (filename) {
        // FishBase images are hosted at fishbase.se
        const imageUrl = `https://www.fishbase.se/images/species/${filename}`;
        if (!imageUrls.includes(imageUrl)) {
          imageUrls.push(imageUrl);
        }
      }
    };

    // Add images in order of preference
    addImageUrl(speciesData.PicPreferredName); // Preferred general image
    addImageUrl(speciesData.PicPreferredNameM); // Preferred male image
    addImageUrl(speciesData.PicPreferredN
FishBaseClient.testConnection method · typescript · L196-L206 (11 LOC)
src/integrations/fishbase.ts
  async testConnection(): Promise<boolean> {
    try {
      // Try a simple species query as a connectivity test
      // Using a common, well-known species
      const result = await this.getSpecies("Poecilia", "reticulata");
      return result !== null;
    } catch (error) {
      logger.error("FishBase API connection test failed", error);
      return false;
    }
  }
getFishBaseClient function · typescript · L217-L225 (9 LOC)
src/integrations/fishbase.ts
export function getFishBaseClient(): FishBaseClient {
  if (!clientInstance) {
    if (!config.fishbase?.enableSync) {
      throw new Error("FishBase integration is disabled in configuration");
    }
    clientInstance = new FishBaseClient();
  }
  return clientInstance;
}
GBIFClient.constructor method · typescript · L122-L144 (23 LOC)
src/integrations/gbif.ts
  constructor(clientConfig?: Partial<IntegrationClientConfig>) {
    const defaultConfig = config.gbif;

    if (!defaultConfig) {
      throw new Error("GBIF configuration not found in config.json");
    }

    // Map config field names to match IntegrationClientConfig
    const integrationConfig: IntegrationClientConfig = {
      baseUrl: defaultConfig.baseUrl,
      rateLimitMs: defaultConfig.rateLimitMs,
      maxRetries: defaultConfig.maxRetries,
      timeoutMs: defaultConfig.timeoutMs,
      enabled: defaultConfig.enableSync,
    };

    super({
      ...integrationConfig,
      ...clientConfig,
    });

    this.logInit();
  }
GBIFClient.matchSpecies method · typescript · L153-L184 (32 LOC)
src/integrations/gbif.ts
  async matchSpecies(genus: string, species: string): Promise<GBIFSpeciesMatch | null> {
    if (!this.isEnabled()) {
      logger.warn("GBIF integration is disabled");
      return null;
    }

    try {
      const scientificName = `${genus} ${species}`;
      const response = await this.get<GBIFSpeciesMatch>("/species/match", {
        name: scientificName,
        verbose: false,
      });

      if (!response) {
        logger.info(`Species not found in GBIF: ${scientificName}`);
        return null;
      }

      // Check if we got a good match
      if (response.matchType === "NONE" || response.confidence < 80) {
        logger.info(
          `Low confidence GBIF match for ${scientificName}: ${response.confidence}% (${response.matchType})`
        );
        return null;
      }

      return response;
    } catch (error) {
      logger.error(`Failed to match species in GBIF for ${genus} ${species}`, error);
      return null;
    }
  }
Want this analysis on your repo? https://repobility.com/scan/
GBIFClient.getSpeciesDetail method · typescript · L192-L204 (13 LOC)
src/integrations/gbif.ts
  async getSpeciesDetail(usageKey: number): Promise<GBIFSpeciesDetail | null> {
    if (!this.isEnabled()) {
      return null;
    }

    try {
      const response = await this.get<GBIFSpeciesDetail>(`/species/${usageKey}`);
      return response;
    } catch (error) {
      logger.error(`Failed to get GBIF species detail for key ${usageKey}`, error);
      return null;
    }
  }
GBIFClient.getSpeciesMedia method · typescript · L213-L237 (25 LOC)
src/integrations/gbif.ts
  async getSpeciesMedia(usageKey: number, limit = 20): Promise<GBIFMedia[]> {
    if (!this.isEnabled()) {
      return [];
    }

    try {
      const response = await this.get<GBIFMediaResponse>(`/species/${usageKey}/media`, {
        limit,
      });

      if (!response || !response.results) {
        return [];
      }

      // Filter to only images (StillImage)
      const images = response.results.filter(
        (media) => media.type === "StillImage" && media.identifier
      );

      return images;
    } catch (error) {
      logger.error(`Failed to get GBIF media for key ${usageKey}`, error);
      return [];
    }
  }
GBIFClient.getExternalData method · typescript · L246-L272 (27 LOC)
src/integrations/gbif.ts
  async getExternalData(genus: string, species: string): Promise<GBIFResult | null> {
    const match = await this.matchSpecies(genus, species);

    if (!match) {
      return null;
    }

    // Construct GBIF species page URL
    const gbifUrl = `https://www.gbif.org/species/${match.usageKey}`;

    // Construct occurrence map URL
    // This is a static map image showing where the species has been observed
    const occurrenceMapUrl = `https://api.gbif.org/v2/map/occurrence/density/0/0/[email protected]?taxonKey=${match.usageKey}&bin=hex&hexPerTile=30&style=purpleYellow.point`;

    // Get images
    const media = await this.getSpeciesMedia(match.usageKey, 10);
    const imageUrls = media.map((m) => m.identifier).filter((url) => url && url.length > 0);

    return {
      usageKey: match.usageKey,
      gbifUrl,
      occurrenceMapUrl,
      imageUrls,
      scientificName: match.canonicalName || match.scientificName,
      confidence: match.confidence,
    };
  }
GBIFClient.testConnection method · typescript · L279-L294 (16 LOC)
src/integrations/gbif.ts
  async testConnection(): Promise<boolean> {
    try {
      // Try to match a common, well-known species
      const result = await this.matchSpecies("Poecilia", "reticulata");
      if (!result) {
        logger.warn("GBIF test query returned no results");
        return false;
      }

      logger.info("GBIF API connection test successful");
      return true;
    } catch (error) {
      logger.error("GBIF API connection test failed", error);
      return false;
    }
  }
getGBIFClient function · typescript · L305-L313 (9 LOC)
src/integrations/gbif.ts
export function getGBIFClient(): GBIFClient {
  if (!clientInstance) {
    if (!config.gbif?.enableSync) {
      throw new Error("GBIF integration is disabled in configuration");
    }
    clientInstance = new GBIFClient();
  }
  return clientInstance;
}
IUCNAPIError.constructor method · typescript · L113-L120 (8 LOC)
src/integrations/iucn.ts
  constructor(
    message: string,
    public statusCode?: number,
    public response?: unknown
  ) {
    super(message);
    this.name = "IUCNAPIError";
  }
IUCNClient.constructor method · typescript · L140-L158 (19 LOC)
src/integrations/iucn.ts
  constructor(clientConfig?: Partial<IUCNClientConfig>) {
    // Load configuration from config.json and merge with overrides
    const defaultConfig = config.iucn;

    if (!defaultConfig || !defaultConfig.apiToken) {
      throw new Error("IUCN configuration not found in config.json");
    }

    this.config = {
      ...defaultConfig,
      ...clientConfig,
    };

    if (this.config.apiToken === "YOUR_IUCN_API_TOKEN_HERE") {
      throw new Error("IUCN API token not configured. Please add your token to config.json");
    }

    logger.info("IUCN API client initialized");
  }
IUCNClient.enforceRateLimit method · typescript · L163-L174 (12 LOC)
src/integrations/iucn.ts
  private async enforceRateLimit(): Promise<void> {
    const now = Date.now();
    const timeSinceLastRequest = now - this.lastRequestTime;

    if (timeSinceLastRequest < this.config.rateLimitMs) {
      const waitTime = this.config.rateLimitMs - timeSinceLastRequest;
      logger.info(`Rate limiting: waiting ${waitTime}ms`);
      await delay(waitTime);
    }

    this.lastRequestTime = Date.now();
  }
Same scanner, your repo: https://repobility.com — Repobility
IUCNClient.request method · typescript · L179-L255 (77 LOC)
src/integrations/iucn.ts
  private async request<T>(
    endpoint: string,
    retryCount = 0
  ): Promise<T | null> {
    await this.enforceRateLimit();

    const url = `${this.config.baseUrl}${endpoint}`;

    logger.info(`IUCN API request: ${endpoint}`);

    try {
      const controller = new AbortController();
      const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);

      const response = await fetch(url, {
        signal: controller.signal,
        headers: {
          Accept: "application/json",
          Authorization: `Bearer ${this.config.apiToken}`,
        },
      });

      clearTimeout(timeout);

      // Handle different status codes
      if (response.status === 404) {
        logger.info(`IUCN API: Species not found (404)`);
        return null;
      }

      if (response.status === 429) {
        // Rate limited
        if (retryCount < this.config.maxRetries) {
          const backoffMs = this.config.rateLimitMs * Math.pow(2, retryCount);
          logger.warn(`
IUCNClient.getSpeciesByName method · typescript · L265-L276 (12 LOC)
src/integrations/iucn.ts
  async getSpeciesByName(scientificName: string): Promise<IUCNSpeciesResult | null> {
    const parts = scientificName.trim().split(/\s+/);
    if (parts.length < 2) {
      logger.warn(`Invalid scientific name format: ${scientificName}`);
      return null;
    }

    const genus = parts[0];
    const species = parts[1];

    return this.getSpecies(genus, species);
  }
IUCNClient.getSpecies method · typescript · L285-L321 (37 LOC)
src/integrations/iucn.ts
  async getSpecies(genus: string, species: string): Promise<IUCNSpeciesResult | null> {
    const encodedGenus = encodeURIComponent(genus);
    const encodedSpecies = encodeURIComponent(species);
    const response = await this.request<IUCNV4TaxonResponse>(
      `/taxa/scientific_name?genus_name=${encodedGenus}&species_name=${encodedSpecies}`
    );

    if (!response || !response.assessments || response.assessments.length === 0) {
      return null;
    }

    // Get the latest assessment
    const latestAssessment = response.assessments.find((a) => a.latest);
    if (!latestAssessment) {
      return null;
    }

    // Convert v4 response to v3-compatible format for backward compatibility
    return {
      taxonid: response.taxon.sis_id,
      scientific_name: response.taxon.scientific_name,
      kingdom: response.taxon.kingdom_name,
      phylum: response.taxon.phylum_name,
      class: response.taxon.class_name,
      order: response.taxon.order_name,
      family: response.tax
IUCNClient.checkIfSynonym method · typescript · L336-L342 (7 LOC)
src/integrations/iucn.ts
  async checkIfSynonym(
    genus: string,
    species: string
  ): Promise<{
    isSynonym: boolean;
    acceptedName: { genus: string; species: string; taxonId: number; url: string } | null;
  }> {
IUCNClient.testConnection method · typescript · L376-L386 (11 LOC)
src/integrations/iucn.ts
  async testConnection(): Promise<boolean> {
    try {
      // Try a simple taxa query as a connectivity test
      // Using a common, well-known species that should always be in the database
      await this.getSpecies("Homo", "sapiens");
      return true;
    } catch (error) {
      logger.error("IUCN API connection test failed", error);
      return false;
    }
  }
getIUCNClient function · typescript · L397-L405 (9 LOC)
src/integrations/iucn.ts
export function getIUCNClient(): IUCNClient {
  if (!clientInstance) {
    if (!config.iucn?.enableSync) {
      throw new Error("IUCN integration is disabled in configuration");
    }
    clientInstance = new IUCNClient();
  }
  return clientInstance;
}
WikipediaClient.constructor method · typescript · L132-L155 (24 LOC)
src/integrations/wikipedia.ts
  constructor(clientConfig?: Partial<IntegrationClientConfig>) {
    const defaultConfig = config.wikipedia;

    if (!defaultConfig) {
      throw new Error("Wikipedia configuration not found in config.json");
    }

    // Map config field names to match IntegrationClientConfig
    const integrationConfig: IntegrationClientConfig = {
      baseUrl: defaultConfig.baseUrl,
      rateLimitMs: defaultConfig.rateLimitMs,
      maxRetries: defaultConfig.maxRetries,
      timeoutMs: defaultConfig.timeoutMs,
      enabled: defaultConfig.enableSync,
    };

    super({
      ...integrationConfig,
      ...clientConfig,
    });

    this.wikidataUrl = defaultConfig.wikidataUrl ?? "https://www.wikidata.org/w/api.php";
    this.logInit();
  }
WikipediaClient.queryWikidata method · typescript · L164-L238 (75 LOC)
src/integrations/wikipedia.ts
  async queryWikidata(genus: string, species: string): Promise<WikidataSpeciesResult[]> {
    if (!this.isEnabled()) {
      logger.warn("Wikipedia/Wikidata integration is disabled");
      return [];
    }

    const scientificName = `${genus} ${species}`;

    // SPARQL query to find species by scientific name
    const sparqlQuery = `
SELECT DISTINCT ?item ?itemLabel ?article ?image WHERE {
  # Find items with this exact taxon name
  ?item wdt:P225 "${scientificName}" .

  # Optional: Get English Wikipedia article
  OPTIONAL {
    ?article schema:about ?item ;
             schema:isPartOf <https://en.wikipedia.org/> .
  }

  # Optional: Get image
  OPTIONAL {
    ?item wdt:P18 ?image .
  }

  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 5
    `.trim();

    try {
      // Wikidata SPARQL endpoint
      const sparqlEndpoint = "https://query.wikidata.org/sparql";

      await this.enforceRateLimit();

      logger.info(`Wikidata SPARQL query for: ${scient
All rows scored by the Repobility analyzer (https://repobility.com)
WikipediaClient.getPageSummary method · typescript · L247-L270 (24 LOC)
src/integrations/wikipedia.ts
  async getPageSummary(title: string, lang = "en"): Promise<WikipediaPageSummary | null> {
    if (!this.isEnabled()) {
      return null;
    }

    try {
      // Wikipedia REST API endpoint for page summary
      const endpoint = `/page/summary/${encodeURIComponent(title)}`;

      // Override baseUrl for this request to use the correct language
      const originalBaseUrl = this.config.baseUrl;
      this.config.baseUrl = `https://${lang}.wikipedia.org/api/rest_v1`;

      const summary = await this.get<WikipediaPageSummary>(endpoint);

      // Restore original baseUrl
      this.config.baseUrl = originalBaseUrl;

      return summary;
    } catch (error) {
      logger.error(`Failed to get Wikipedia page summary for ${title}`, error);
      return null;
    }
  }
WikipediaClient.getExternalData method · typescript · L279-L350 (72 LOC)
src/integrations/wikipedia.ts
  async getExternalData(genus: string, species: string): Promise<WikipediaResult | null> {
    const wikidataResults = await this.queryWikidata(genus, species);

    if (wikidataResults.length === 0) {
      return null;
    }

    // Use the first result (most relevant)
    const primaryResult = wikidataResults[0];

    // Extract Wikidata ID from URL
    const wikidataUrlMatch = primaryResult.item.value.match(/Q\d+$/);
    if (!wikidataUrlMatch) {
      logger.warn("Could not extract Wikidata ID from URL");
      return null;
    }

    const wikidataId = wikidataUrlMatch[0];
    const wikidataUrl = primaryResult.item.value;

    // Collect Wikipedia article URLs (try multiple languages)
    const wikipediaUrls: Record<string, string> = {};

    // If we have an English article from SPARQL, add it
    if (primaryResult.article) {
      wikipediaUrls.en = primaryResult.article.value;
    }

    // Try to get page summary for more details and images
    const scientificName = `${genus}
WikipediaClient.testConnection method · typescript · L357-L379 (23 LOC)
src/integrations/wikipedia.ts
  async testConnection(): Promise<boolean> {
    try {
      // Test Wikidata SPARQL
      const wikidataResults = await this.queryWikidata("Poecilia", "reticulata");
      if (wikidataResults.length === 0) {
        logger.warn("Wikidata test query returned no results");
        return false;
      }

      // Test Wikipedia REST API
      const pageSummary = await this.getPageSummary("Poecilia reticulata", "en");
      if (!pageSummary) {
        logger.warn("Wikipedia test query returned no results");
        return false;
      }

      logger.info("Wikipedia/Wikidata API connection test successful");
      return true;
    } catch (error) {
      logger.error("Wikipedia/Wikidata API connection test failed", error);
      return false;
    }
  }
getWikipediaClient function · typescript · L390-L398 (9 LOC)
src/integrations/wikipedia.ts
export function getWikipediaClient(): WikipediaClient {
  if (!clientInstance) {
    if (!config.wikipedia?.enableSync) {
      throw new Error("Wikipedia integration is disabled in configuration");
    }
    clientInstance = new WikipediaClient();
  }
  return clientInstance;
}
checkAndUpdateMemberLevel function · typescript · L18-L84 (67 LOC)
src/levelManager.ts
export async function checkAndUpdateMemberLevel(
  memberId: number,
  program: Program,
  options?: { disableEmails?: boolean }
): Promise<LevelCheckResult> {
  try {
    const member = await getMember(memberId);
    if (!member) {
      throw new Error(`Member ${memberId} not found`);
    }

    // Get all approved submissions for this member and program
    const submissions = await getSubmissionsByMember(
      memberId,
      false, // don't include unsubmitted
      false // don't include unapproved
    );

    // Filter submissions by program and extract points
    const programSubmissions = submissions.filter((sub) => sub.program === program);
    const pointsArray = programSubmissions.map((sub) => sub.total_points || sub.points || 0);

    // Calculate what level they should be
    const calculatedLevel = calculateLevel(levelRules[program], pointsArray);

    // Get current stored level
    const currentLevel = getCurrentLevel(member, program);

    // Check if level has chang
checkAllMemberLevels function · typescript · L89-L96 (8 LOC)
src/levelManager.ts
export async function checkAllMemberLevels(
  memberId: number,
  options?: { disableEmails?: boolean }
): Promise<{
  fish?: LevelCheckResult;
  plant?: LevelCheckResult;
  coral?: LevelCheckResult;
}> {
getCurrentLevel function · typescript · L114-L125 (12 LOC)
src/levelManager.ts
function getCurrentLevel(member: MemberRecord, program: Program): string | undefined {
  switch (program) {
    case "fish":
      return member.fish_level;
    case "plant":
      return member.plant_level;
    case "coral":
      return member.coral_level;
    default:
      return undefined;
  }
}
shouldSendUpgradeEmail function · typescript · L131-L144 (14 LOC)
src/levelManager.ts
function shouldSendUpgradeEmail(oldLevel: string | undefined, newLevel: string): boolean {
  // Always send if going from null/undefined to a level
  if (!oldLevel && newLevel) {
    return true;
  }

  // Don't send if both are null/undefined
  if (!oldLevel && !newLevel) {
    return false;
  }

  // For now, send for any level change (could add level hierarchy checking later)
  return oldLevel !== newLevel;
}
Source: Repobility analyzer · https://repobility.com
normalizeDateString function · typescript · L129-L184 (56 LOC)
src/mcp/backfill-server-core.ts
function normalizeDateString(input: string | undefined): string | null {
  if (!input || !input.trim()) return null;

  const trimmed = input.trim();

  // ISO date passthrough (YYYY-MM-DD)
  if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
    return trimmed;
  }

  // MM/DD/YYYY or M/D/YYYY
  const mdyMatch = trimmed.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
  if (mdyMatch) {
    const month = mdyMatch[1].padStart(2, "0");
    const day = mdyMatch[2].padStart(2, "0");
    return `${mdyMatch[3]}-${month}-${day}`;
  }

  const lower = trimmed.toLowerCase();

  // "Mid April 2024" → 2024-04-15
  const midMatch = lower.match(/^mid\s+(\w+)\s+(\d{4})$/);
  if (midMatch) {
    const month = MONTH_MAP[midMatch[1]];
    if (month) {
      return `${midMatch[2]}-${String(month).padStart(2, "0")}-15`;
    }
  }

  // "June/July 2024" or "June-July 2024" → midpoint of first month
  const rangeMatch = lower.match(/^(\w+)\s*[-/]\s*(\w+)\s+(\d{4})$/);
  if (rangeMatch) {
    const month = MONTH_MAP[range
normalizeWaterType function · typescript · L186-L195 (10 LOC)
src/mcp/backfill-server-core.ts
function normalizeWaterType(input: string | undefined): string | null {
  if (!input || !input.trim()) return null;
  const lower = input.trim().toLowerCase();
  if (lower === "freshwater" || lower === "fresh") return "Fresh";
  if (lower === "brackish") return "Brackish";
  if (lower === "saltwater" || lower === "salt" || lower === "marine") return "Salt";
  // Return as-is if it's already a valid value
  if (["Fresh", "Brackish", "Salt"].includes(input.trim())) return input.trim();
  return input.trim();
}
normalizeNullLike function · typescript · L197-L215 (19 LOC)
src/mcp/backfill-server-core.ts
function normalizeNullLike(input: string | undefined): string | null {
  if (!input) return null;
  const lower = input.trim().toLowerCase();
  if (
    lower === "" ||
    lower === "n/a" ||
    lower === "na" ||
    lower === "none" ||
    lower === "dont test" ||
    lower === "don't test" ||
    lower === "unknown" ||
    lower === "not tested" ||
    lower === "-" ||
    lower === "?"
  ) {
    return null;
  }
  return input.trim();
}
‹ prevpage 6 / 10next ›